diff --git a/.gitignore b/.gitignore index 45a2c769..55615686 100644 --- a/.gitignore +++ b/.gitignore @@ -160,5 +160,7 @@ gradle-app.setting # End of https://www.gitignore.io/api/java,macos,gradle,intellij+all hospitalDB - /gargoyle_food_request_db/ +/flowerAPI_DB/ +/myDB/ +/giftServiceDB/ diff --git a/build.gradle b/build.gradle index a35eb3c7..cad2cc88 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,16 @@ dependencies { [group: 'javax.mail', name: 'mail', version: '1.4.1'], [group: 'edu.wpi.cs3733.d18.teamG', name: 'FoodRequest', version:'1.0.0'], [group: 'org.twitter4j', name: 'twitter4j-core', version: '4.0.1'], - [group: 'com.github.dvdme', name: 'ForecastIOLib', version: '1.5.2'] + [group: 'com.github.dvdme', name: 'ForecastIOLib', version: '1.5.2'], + [group: 'edu.wpi.cs3733.c20.teamS', name: 'GiftRequest', version:'1.0.2'], + [group: 'com.fazecast', name: 'jSerialComm', version:'2.6.0'], + [group: 'com.neuronrobotics', name: 'nrjavaserial', version: '3.7.5.1'], + [group: 'edu.wpi.cs3733.c20.teamS', name: 'GiftRequest', version:'1.0.2'], + [group: 'edu.wpi.cs3733.c20.teamR', name: 'AppointmentRequest', version:'1.6.9'], + [group: 'edu.wpi.cs3733.c20.teamU', name: 'FlowerRequestS', version:'1.0.1'], + [group: 'edu.wpi.cs3733.c20.teamV', name: 'TeamVInterpreterRequest', version:'1.1.0'], + [group: 'edu.wpi.cs3733.c20.teamT', name: 'ReligiousServiceAPI', version:'1.0.1'], + [group: 'io.github.typhon0', name: 'AnimateFX', version: '1.2.0'] ) compileOnly( @@ -78,8 +87,8 @@ jacocoTestCoverageVerification { minimum = 1.0 } excludes = [ - 'edu.wpi.teamname.App', - 'edu.wpi.teamname.Main' + 'edu.wpi.teamname.App', + 'edu.wpi.teamname.Main' ] } diff --git a/giftServiceDB/README_DO_NOT_TOUCH_FILES.txt b/giftServiceDB/README_DO_NOT_TOUCH_FILES.txt new file mode 100644 index 00000000..a4bc1452 --- /dev/null +++ b/giftServiceDB/README_DO_NOT_TOUCH_FILES.txt @@ -0,0 +1,9 @@ + +# ************************************************************************* +# *** DO NOT TOUCH FILES IN THIS DIRECTORY! *** +# *** FILES IN THIS DIRECTORY AND SUBDIRECTORIES CONSTITUTE A DERBY *** +# *** DATABASE, WHICH INCLUDES THE DATA (USER AND SYSTEM) AND THE *** +# *** FILES NECESSARY FOR DATABASE RECOVERY. *** +# *** EDITING, ADDING, OR DELETING ANY OF THESE FILES MAY CAUSE DATA *** +# *** CORRUPTION AND LEAVE THE DATABASE IN A NON-RECOVERABLE STATE. *** +# ************************************************************************* \ No newline at end of file diff --git a/giftServiceDB/db.lck b/giftServiceDB/db.lck new file mode 100644 index 00000000..16d46247 Binary files /dev/null and b/giftServiceDB/db.lck differ diff --git a/giftServiceDB/log/README_DO_NOT_TOUCH_FILES.txt b/giftServiceDB/log/README_DO_NOT_TOUCH_FILES.txt new file mode 100644 index 00000000..56df292f --- /dev/null +++ b/giftServiceDB/log/README_DO_NOT_TOUCH_FILES.txt @@ -0,0 +1,8 @@ + +# ************************************************************************* +# *** DO NOT TOUCH FILES IN THIS DIRECTORY! *** +# *** FILES IN THIS DIRECTORY ARE USED BY THE DERBY DATABASE RECOVERY *** +# *** SYSTEM. EDITING, ADDING, OR DELETING FILES IN THIS DIRECTORY *** +# *** WILL CAUSE THE DERBY RECOVERY SYSTEM TO FAIL, LEADING TO *** +# *** NON-RECOVERABLE CORRUPT DATABASES. *** +# ************************************************************************* \ No newline at end of file diff --git a/giftServiceDB/log/log.ctrl b/giftServiceDB/log/log.ctrl new file mode 100644 index 00000000..62d50d67 Binary files /dev/null and b/giftServiceDB/log/log.ctrl differ diff --git a/giftServiceDB/log/log1.dat b/giftServiceDB/log/log1.dat new file mode 100644 index 00000000..dabaa3ee Binary files /dev/null and b/giftServiceDB/log/log1.dat differ diff --git a/giftServiceDB/log/logmirror.ctrl b/giftServiceDB/log/logmirror.ctrl new file mode 100644 index 00000000..62d50d67 Binary files /dev/null and b/giftServiceDB/log/logmirror.ctrl differ diff --git a/giftServiceDB/seg0/README_DO_NOT_TOUCH_FILES.txt b/giftServiceDB/seg0/README_DO_NOT_TOUCH_FILES.txt new file mode 100644 index 00000000..2bdad061 --- /dev/null +++ b/giftServiceDB/seg0/README_DO_NOT_TOUCH_FILES.txt @@ -0,0 +1,8 @@ + +# ************************************************************************* +# *** DO NOT TOUCH FILES IN THIS DIRECTORY! *** +# *** FILES IN THIS DIRECTORY ARE USED BY THE DERBY DATABASE TO STORE *** +# *** USER AND SYSTEM DATA. EDITING, ADDING, OR DELETING FILES IN THIS *** +# *** DIRECTORY WILL CORRUPT THE ASSOCIATED DERBY DATABASE AND MAKE *** +# *** IT NON-RECOVERABLE. *** +# ************************************************************************* \ No newline at end of file diff --git a/giftServiceDB/seg0/c10.dat b/giftServiceDB/seg0/c10.dat new file mode 100644 index 00000000..233bd06e Binary files /dev/null and b/giftServiceDB/seg0/c10.dat differ diff --git a/giftServiceDB/seg0/c101.dat b/giftServiceDB/seg0/c101.dat new file mode 100644 index 00000000..253ac6d9 Binary files /dev/null and b/giftServiceDB/seg0/c101.dat differ diff --git a/giftServiceDB/seg0/c111.dat b/giftServiceDB/seg0/c111.dat new file mode 100644 index 00000000..ef69c129 Binary files /dev/null and b/giftServiceDB/seg0/c111.dat differ diff --git a/giftServiceDB/seg0/c121.dat b/giftServiceDB/seg0/c121.dat new file mode 100644 index 00000000..145d5719 Binary files /dev/null and b/giftServiceDB/seg0/c121.dat differ diff --git a/giftServiceDB/seg0/c130.dat b/giftServiceDB/seg0/c130.dat new file mode 100644 index 00000000..12dbf333 Binary files /dev/null and b/giftServiceDB/seg0/c130.dat differ diff --git a/giftServiceDB/seg0/c141.dat b/giftServiceDB/seg0/c141.dat new file mode 100644 index 00000000..c58517df Binary files /dev/null and b/giftServiceDB/seg0/c141.dat differ diff --git a/giftServiceDB/seg0/c150.dat b/giftServiceDB/seg0/c150.dat new file mode 100644 index 00000000..a6e79d32 Binary files /dev/null and b/giftServiceDB/seg0/c150.dat differ diff --git a/giftServiceDB/seg0/c161.dat b/giftServiceDB/seg0/c161.dat new file mode 100644 index 00000000..6c78adb9 Binary files /dev/null and b/giftServiceDB/seg0/c161.dat differ diff --git a/giftServiceDB/seg0/c171.dat b/giftServiceDB/seg0/c171.dat new file mode 100644 index 00000000..21ae1e26 Binary files /dev/null and b/giftServiceDB/seg0/c171.dat differ diff --git a/giftServiceDB/seg0/c180.dat b/giftServiceDB/seg0/c180.dat new file mode 100644 index 00000000..16c838c3 Binary files /dev/null and b/giftServiceDB/seg0/c180.dat differ diff --git a/giftServiceDB/seg0/c191.dat b/giftServiceDB/seg0/c191.dat new file mode 100644 index 00000000..5e31e3be Binary files /dev/null and b/giftServiceDB/seg0/c191.dat differ diff --git a/giftServiceDB/seg0/c1a1.dat b/giftServiceDB/seg0/c1a1.dat new file mode 100644 index 00000000..4e7e3a73 Binary files /dev/null and b/giftServiceDB/seg0/c1a1.dat differ diff --git a/giftServiceDB/seg0/c1b1.dat b/giftServiceDB/seg0/c1b1.dat new file mode 100644 index 00000000..bfc318c2 Binary files /dev/null and b/giftServiceDB/seg0/c1b1.dat differ diff --git a/giftServiceDB/seg0/c1c0.dat b/giftServiceDB/seg0/c1c0.dat new file mode 100644 index 00000000..c5b91e2c Binary files /dev/null and b/giftServiceDB/seg0/c1c0.dat differ diff --git a/giftServiceDB/seg0/c1d1.dat b/giftServiceDB/seg0/c1d1.dat new file mode 100644 index 00000000..451f02f4 Binary files /dev/null and b/giftServiceDB/seg0/c1d1.dat differ diff --git a/giftServiceDB/seg0/c1e0.dat b/giftServiceDB/seg0/c1e0.dat new file mode 100644 index 00000000..761408d3 Binary files /dev/null and b/giftServiceDB/seg0/c1e0.dat differ diff --git a/giftServiceDB/seg0/c1f1.dat b/giftServiceDB/seg0/c1f1.dat new file mode 100644 index 00000000..78d701f4 Binary files /dev/null and b/giftServiceDB/seg0/c1f1.dat differ diff --git a/giftServiceDB/seg0/c20.dat b/giftServiceDB/seg0/c20.dat new file mode 100644 index 00000000..a6508dad Binary files /dev/null and b/giftServiceDB/seg0/c20.dat differ diff --git a/giftServiceDB/seg0/c200.dat b/giftServiceDB/seg0/c200.dat new file mode 100644 index 00000000..6a03224e Binary files /dev/null and b/giftServiceDB/seg0/c200.dat differ diff --git a/giftServiceDB/seg0/c211.dat b/giftServiceDB/seg0/c211.dat new file mode 100644 index 00000000..74fbd5a7 Binary files /dev/null and b/giftServiceDB/seg0/c211.dat differ diff --git a/giftServiceDB/seg0/c221.dat b/giftServiceDB/seg0/c221.dat new file mode 100644 index 00000000..c09fc6d9 Binary files /dev/null and b/giftServiceDB/seg0/c221.dat differ diff --git a/giftServiceDB/seg0/c230.dat b/giftServiceDB/seg0/c230.dat new file mode 100644 index 00000000..a36ef39f Binary files /dev/null and b/giftServiceDB/seg0/c230.dat differ diff --git a/giftServiceDB/seg0/c241.dat b/giftServiceDB/seg0/c241.dat new file mode 100644 index 00000000..4fd43b2c Binary files /dev/null and b/giftServiceDB/seg0/c241.dat differ diff --git a/giftServiceDB/seg0/c251.dat b/giftServiceDB/seg0/c251.dat new file mode 100644 index 00000000..c6fab1e7 Binary files /dev/null and b/giftServiceDB/seg0/c251.dat differ diff --git a/giftServiceDB/seg0/c260.dat b/giftServiceDB/seg0/c260.dat new file mode 100644 index 00000000..25f81fde Binary files /dev/null and b/giftServiceDB/seg0/c260.dat differ diff --git a/giftServiceDB/seg0/c271.dat b/giftServiceDB/seg0/c271.dat new file mode 100644 index 00000000..51cde573 Binary files /dev/null and b/giftServiceDB/seg0/c271.dat differ diff --git a/giftServiceDB/seg0/c281.dat b/giftServiceDB/seg0/c281.dat new file mode 100644 index 00000000..cfed875d Binary files /dev/null and b/giftServiceDB/seg0/c281.dat differ diff --git a/giftServiceDB/seg0/c290.dat b/giftServiceDB/seg0/c290.dat new file mode 100644 index 00000000..a85589e5 Binary files /dev/null and b/giftServiceDB/seg0/c290.dat differ diff --git a/giftServiceDB/seg0/c2a1.dat b/giftServiceDB/seg0/c2a1.dat new file mode 100644 index 00000000..8e2ed6af Binary files /dev/null and b/giftServiceDB/seg0/c2a1.dat differ diff --git a/giftServiceDB/seg0/c2b1.dat b/giftServiceDB/seg0/c2b1.dat new file mode 100644 index 00000000..2a296924 Binary files /dev/null and b/giftServiceDB/seg0/c2b1.dat differ diff --git a/giftServiceDB/seg0/c2c1.dat b/giftServiceDB/seg0/c2c1.dat new file mode 100644 index 00000000..5511575f Binary files /dev/null and b/giftServiceDB/seg0/c2c1.dat differ diff --git a/giftServiceDB/seg0/c2d0.dat b/giftServiceDB/seg0/c2d0.dat new file mode 100644 index 00000000..4adc6e44 Binary files /dev/null and b/giftServiceDB/seg0/c2d0.dat differ diff --git a/giftServiceDB/seg0/c2e1.dat b/giftServiceDB/seg0/c2e1.dat new file mode 100644 index 00000000..b37b9b25 Binary files /dev/null and b/giftServiceDB/seg0/c2e1.dat differ diff --git a/giftServiceDB/seg0/c2f0.dat b/giftServiceDB/seg0/c2f0.dat new file mode 100644 index 00000000..d854b4b4 Binary files /dev/null and b/giftServiceDB/seg0/c2f0.dat differ diff --git a/giftServiceDB/seg0/c300.dat b/giftServiceDB/seg0/c300.dat new file mode 100644 index 00000000..2053e010 Binary files /dev/null and b/giftServiceDB/seg0/c300.dat differ diff --git a/giftServiceDB/seg0/c31.dat b/giftServiceDB/seg0/c31.dat new file mode 100644 index 00000000..e05feb12 Binary files /dev/null and b/giftServiceDB/seg0/c31.dat differ diff --git a/giftServiceDB/seg0/c311.dat b/giftServiceDB/seg0/c311.dat new file mode 100644 index 00000000..f60c260f Binary files /dev/null and b/giftServiceDB/seg0/c311.dat differ diff --git a/giftServiceDB/seg0/c321.dat b/giftServiceDB/seg0/c321.dat new file mode 100644 index 00000000..a9d74536 Binary files /dev/null and b/giftServiceDB/seg0/c321.dat differ diff --git a/giftServiceDB/seg0/c331.dat b/giftServiceDB/seg0/c331.dat new file mode 100644 index 00000000..85ee72b3 Binary files /dev/null and b/giftServiceDB/seg0/c331.dat differ diff --git a/giftServiceDB/seg0/c340.dat b/giftServiceDB/seg0/c340.dat new file mode 100644 index 00000000..d99b11a3 Binary files /dev/null and b/giftServiceDB/seg0/c340.dat differ diff --git a/giftServiceDB/seg0/c351.dat b/giftServiceDB/seg0/c351.dat new file mode 100644 index 00000000..f822f4cb Binary files /dev/null and b/giftServiceDB/seg0/c351.dat differ diff --git a/giftServiceDB/seg0/c361.dat b/giftServiceDB/seg0/c361.dat new file mode 100644 index 00000000..b5c8f259 Binary files /dev/null and b/giftServiceDB/seg0/c361.dat differ diff --git a/giftServiceDB/seg0/c371.dat b/giftServiceDB/seg0/c371.dat new file mode 100644 index 00000000..ad11f01b Binary files /dev/null and b/giftServiceDB/seg0/c371.dat differ diff --git a/giftServiceDB/seg0/c380.dat b/giftServiceDB/seg0/c380.dat new file mode 100644 index 00000000..08f818e7 Binary files /dev/null and b/giftServiceDB/seg0/c380.dat differ diff --git a/giftServiceDB/seg0/c391.dat b/giftServiceDB/seg0/c391.dat new file mode 100644 index 00000000..a2f0d99a Binary files /dev/null and b/giftServiceDB/seg0/c391.dat differ diff --git a/giftServiceDB/seg0/c3a1.dat b/giftServiceDB/seg0/c3a1.dat new file mode 100644 index 00000000..34dfa8e9 Binary files /dev/null and b/giftServiceDB/seg0/c3a1.dat differ diff --git a/giftServiceDB/seg0/c3b1.dat b/giftServiceDB/seg0/c3b1.dat new file mode 100644 index 00000000..d962a117 Binary files /dev/null and b/giftServiceDB/seg0/c3b1.dat differ diff --git a/giftServiceDB/seg0/c3c0.dat b/giftServiceDB/seg0/c3c0.dat new file mode 100644 index 00000000..4d061cf0 Binary files /dev/null and b/giftServiceDB/seg0/c3c0.dat differ diff --git a/giftServiceDB/seg0/c3d1.dat b/giftServiceDB/seg0/c3d1.dat new file mode 100644 index 00000000..45c9fa24 Binary files /dev/null and b/giftServiceDB/seg0/c3d1.dat differ diff --git a/giftServiceDB/seg0/c3e1.dat b/giftServiceDB/seg0/c3e1.dat new file mode 100644 index 00000000..48f53e68 Binary files /dev/null and b/giftServiceDB/seg0/c3e1.dat differ diff --git a/giftServiceDB/seg0/c3f1.dat b/giftServiceDB/seg0/c3f1.dat new file mode 100644 index 00000000..08acdcee Binary files /dev/null and b/giftServiceDB/seg0/c3f1.dat differ diff --git a/giftServiceDB/seg0/c400.dat b/giftServiceDB/seg0/c400.dat new file mode 100644 index 00000000..b6dcadb8 Binary files /dev/null and b/giftServiceDB/seg0/c400.dat differ diff --git a/giftServiceDB/seg0/c41.dat b/giftServiceDB/seg0/c41.dat new file mode 100644 index 00000000..c44cf2c6 Binary files /dev/null and b/giftServiceDB/seg0/c41.dat differ diff --git a/giftServiceDB/seg0/c411.dat b/giftServiceDB/seg0/c411.dat new file mode 100644 index 00000000..6f95d26f Binary files /dev/null and b/giftServiceDB/seg0/c411.dat differ diff --git a/giftServiceDB/seg0/c421.dat b/giftServiceDB/seg0/c421.dat new file mode 100644 index 00000000..179426ab Binary files /dev/null and b/giftServiceDB/seg0/c421.dat differ diff --git a/giftServiceDB/seg0/c430.dat b/giftServiceDB/seg0/c430.dat new file mode 100644 index 00000000..55c948db Binary files /dev/null and b/giftServiceDB/seg0/c430.dat differ diff --git a/giftServiceDB/seg0/c441.dat b/giftServiceDB/seg0/c441.dat new file mode 100644 index 00000000..3948b2a3 Binary files /dev/null and b/giftServiceDB/seg0/c441.dat differ diff --git a/giftServiceDB/seg0/c451.dat b/giftServiceDB/seg0/c451.dat new file mode 100644 index 00000000..fe1ab73e Binary files /dev/null and b/giftServiceDB/seg0/c451.dat differ diff --git a/giftServiceDB/seg0/c461.dat b/giftServiceDB/seg0/c461.dat new file mode 100644 index 00000000..e6d98541 Binary files /dev/null and b/giftServiceDB/seg0/c461.dat differ diff --git a/giftServiceDB/seg0/c470.dat b/giftServiceDB/seg0/c470.dat new file mode 100644 index 00000000..c9f2eb1c Binary files /dev/null and b/giftServiceDB/seg0/c470.dat differ diff --git a/giftServiceDB/seg0/c481.dat b/giftServiceDB/seg0/c481.dat new file mode 100644 index 00000000..397b2917 Binary files /dev/null and b/giftServiceDB/seg0/c481.dat differ diff --git a/giftServiceDB/seg0/c51.dat b/giftServiceDB/seg0/c51.dat new file mode 100644 index 00000000..29f3cb60 Binary files /dev/null and b/giftServiceDB/seg0/c51.dat differ diff --git a/giftServiceDB/seg0/c60.dat b/giftServiceDB/seg0/c60.dat new file mode 100644 index 00000000..ba625cec Binary files /dev/null and b/giftServiceDB/seg0/c60.dat differ diff --git a/giftServiceDB/seg0/c71.dat b/giftServiceDB/seg0/c71.dat new file mode 100644 index 00000000..0cdbc3dd Binary files /dev/null and b/giftServiceDB/seg0/c71.dat differ diff --git a/giftServiceDB/seg0/c81.dat b/giftServiceDB/seg0/c81.dat new file mode 100644 index 00000000..191cb77c Binary files /dev/null and b/giftServiceDB/seg0/c81.dat differ diff --git a/giftServiceDB/seg0/c90.dat b/giftServiceDB/seg0/c90.dat new file mode 100644 index 00000000..0e0d76d8 Binary files /dev/null and b/giftServiceDB/seg0/c90.dat differ diff --git a/giftServiceDB/seg0/ca1.dat b/giftServiceDB/seg0/ca1.dat new file mode 100644 index 00000000..626109f0 Binary files /dev/null and b/giftServiceDB/seg0/ca1.dat differ diff --git a/giftServiceDB/seg0/cb1.dat b/giftServiceDB/seg0/cb1.dat new file mode 100644 index 00000000..194d7f8b Binary files /dev/null and b/giftServiceDB/seg0/cb1.dat differ diff --git a/giftServiceDB/seg0/cc0.dat b/giftServiceDB/seg0/cc0.dat new file mode 100644 index 00000000..22687200 Binary files /dev/null and b/giftServiceDB/seg0/cc0.dat differ diff --git a/giftServiceDB/seg0/cd1.dat b/giftServiceDB/seg0/cd1.dat new file mode 100644 index 00000000..d919a1b0 Binary files /dev/null and b/giftServiceDB/seg0/cd1.dat differ diff --git a/giftServiceDB/seg0/ce1.dat b/giftServiceDB/seg0/ce1.dat new file mode 100644 index 00000000..299e0c40 Binary files /dev/null and b/giftServiceDB/seg0/ce1.dat differ diff --git a/giftServiceDB/seg0/cf0.dat b/giftServiceDB/seg0/cf0.dat new file mode 100644 index 00000000..408eaf95 Binary files /dev/null and b/giftServiceDB/seg0/cf0.dat differ diff --git a/giftServiceDB/service.properties b/giftServiceDB/service.properties new file mode 100644 index 00000000..19070518 --- /dev/null +++ b/giftServiceDB/service.properties @@ -0,0 +1,23 @@ +#D:\Classes\Software Engineering\Repository\Project-Team-S-master\giftServiceDB +# ******************************************************************** +# *** Please do NOT edit this file. *** +# *** CHANGING THE CONTENT OF THIS FILE MAY CAUSE DATA CORRUPTION. *** +# ******************************************************************** +#Sat Feb 29 16:39:02 EST 2020 +SysschemasIndex2Identifier=225 +SyscolumnsIdentifier=144 +SysconglomeratesIndex1Identifier=49 +SysconglomeratesIdentifier=32 +SyscolumnsIndex2Identifier=177 +SysschemasIndex1Identifier=209 +SysconglomeratesIndex3Identifier=81 +SystablesIndex2Identifier=129 +SyscolumnsIndex1Identifier=161 +derby.serviceProtocol=org.apache.derby.database.Database +SysschemasIdentifier=192 +derby.storage.propertiesId=16 +SysconglomeratesIndex2Identifier=65 +derby.serviceLocale=en_US +SystablesIdentifier=96 +SystablesIndex1Identifier=113 +#--- last line, don't put anything after this line --- diff --git a/libs/jSerialComm-2.6.0.jar b/libs/jSerialComm-2.6.0.jar new file mode 100644 index 00000000..3412cf90 Binary files /dev/null and b/libs/jSerialComm-2.6.0.jar differ diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/AboutMeController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/AboutMeController.java index 342574ac..bdcc3223 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/AboutMeController.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/AboutMeController.java @@ -5,14 +5,22 @@ import edu.wpi.cs3733.c20.teamS.serviceRequests.InterpreterServiceRequest; import io.reactivex.rxjava3.subjects.PublishSubject; import javafx.event.ActionEvent; +import javafx.event.Event; import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; import javafx.scene.layout.AnchorPane; +import javafx.stage.Modality; import javafx.stage.Stage; +import java.io.IOException; import java.net.MalformedURLException; +import java.net.URL; +import java.util.ResourceBundle; public class AboutMeController { @@ -22,6 +30,13 @@ public class AboutMeController { @FXML private JFXButton goBack; + @FXML + private JFXButton goCredits; + + @FXML + private ImageView imageV; + + @FXML @@ -33,6 +48,35 @@ void BackClicked() { + //Open up Credits Page + @FXML + void goToCredits(){ + try { + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/FXML/CreditsPage.fxml")); + Parent root = fxmlLoader.load(); + //Parent root1 = fxmlLoader.getRoot(); + Stage window = new Stage(); + window.initModality(Modality.WINDOW_MODAL); + window.setFullScreen(false); + window.setScene(new Scene(root)); + window.setResizable(false); + window.show(); + + Stage stage = (Stage) goBack.getScene().getWindow(); + Settings.openWindows.add(window); + BaseScreen.puggy.register(window.getScene(), Event.ANY); + + // do what you have to do + stage.close(); + + } catch (IOException e) { + System.out.println("Can't load new window"); + } + + } + + + public AboutMeController(){} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/App.java b/src/main/java/edu/wpi/cs3733/c20/teamS/App.java index c0eaec61..1eb0a1f5 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/App.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/App.java @@ -1,20 +1,8 @@ package edu.wpi.cs3733.c20.teamS; -import edu.wpi.cs3733.c20.teamS.database.DatabaseController; -import edu.wpi.cs3733.c20.teamS.database.ServiceData; -import edu.wpi.cs3733.c20.teamS.serviceRequests.*; import javafx.application.Application; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.layout.BorderPane; import javafx.stage.Stage; -import java.util.HashSet; -import java.util.Set; - public class App extends Application { @Override @@ -34,6 +22,5 @@ public void start(Stage primaryStage) throws Exception { // testSet.add(testServiceRequest2); // ActiveServiceRequestScreen testScreen = new ActiveServiceRequestScreen(primaryStage, testSet); - } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/BaseScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/BaseScreen.java new file mode 100644 index 00000000..5046599e --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/BaseScreen.java @@ -0,0 +1,33 @@ +package edu.wpi.cs3733.c20.teamS; + +import edu.wpi.cs3733.c20.teamS.emergency.EmergencyScreen; +import edu.wpi.cs3733.c20.teamS.utilities.FireWatchDog; +import edu.wpi.cs3733.c20.teamS.utilities.UIWatchPug; +import javafx.util.Duration; + +public abstract class BaseScreen { + public static final UIWatchPug puggy; + //public static final FireWatchDog fireWatch; + + static { + //Stage stage = new Stage(); + puggy = new UIWatchPug(new Duration(130000),() -> { + MainStartScreen.showDialog(); + }); + +// fireWatch = new FireWatchDog(new Duration(1000),()->{ +// if(SerialPoller.runSensor()){ +// //System.out.println("Emergency Detected"); +// EmergencyScreen es = new EmergencyScreen(); +// }else{ +// //System.out.println("No emergency"); +// } +// +//// SerialPoller.serial.getInputStream(). +// +// }); + } + + //public void close(){} +} + diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/CreditsPageController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/CreditsPageController.java new file mode 100644 index 00000000..befc7fa2 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/CreditsPageController.java @@ -0,0 +1,45 @@ +package edu.wpi.cs3733.c20.teamS; + +import com.jfoenix.controls.JFXButton; +import javafx.event.Event; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Modality; +import javafx.stage.Stage; + +import java.io.IOException; + +public class CreditsPageController { + + @FXML + JFXButton goBackButton; + + + @FXML + void GoBack() { + Stage stage = (Stage) goBackButton.getScene().getWindow(); + // do what you have to do + stage.close(); + try { + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/FXML/AboutMe.fxml")); + Parent root = (Parent) fxmlLoader.load(); + //Parent root1 = fxmlLoader.getRoot(); + Stage window = new Stage(); + window.initModality(Modality.WINDOW_MODAL); + window.setFullScreen(false); + window.setScene(new Scene(root)); + window.setResizable(false); + + + window.show(); + } catch (IOException e) { + System.out.println("Can't load new window"); + } + + } + + public CreditsPageController(){} + +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/EditScreenController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/EditScreenController.java index 62b234f1..c32e0d7e 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/EditScreenController.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/EditScreenController.java @@ -1,257 +1,282 @@ package edu.wpi.cs3733.c20.teamS.Editing; -import com.google.common.graph.EndpointPair; import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXTextField; +import com.sun.javafx.css.StyleManager; +import edu.wpi.cs3733.c20.teamS.BaseScreen; import edu.wpi.cs3733.c20.teamS.Editing.tools.*; +import edu.wpi.cs3733.c20.teamS.MainToLoginScreen; import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.app.EmployeeEditor.EmployeeEditingScreen; -import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import edu.wpi.cs3733.c20.teamS.app.serviceRequests.ActiveServiceRequestScreen; import edu.wpi.cs3733.c20.teamS.collisionMasks.HitboxRepository; import edu.wpi.cs3733.c20.teamS.collisionMasks.ResourceFolderHitboxRepository; +import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import edu.wpi.cs3733.c20.teamS.database.DatabaseController; import edu.wpi.cs3733.c20.teamS.database.EdgeData; -import edu.wpi.cs3733.c20.teamS.pathDisplaying.MapZoomer; - -import edu.wpi.cs3733.c20.teamS.app.serviceRequests.ActiveServiceRequestScreen; -import edu.wpi.cs3733.c20.teamS.database.ServiceData; -import edu.wpi.cs3733.c20.teamS.serviceRequests.*; - +import edu.wpi.cs3733.c20.teamS.pathDisplaying.Floor; +import edu.wpi.cs3733.c20.teamS.pathDisplaying.FloorSelector; +import edu.wpi.cs3733.c20.teamS.serviceRequests.AccessLevel; import edu.wpi.cs3733.c20.teamS.serviceRequests.Employee; import edu.wpi.cs3733.c20.teamS.serviceRequests.SelectServiceScreen; - -import edu.wpi.cs3733.c20.teamS.database.DatabaseController; -import edu.wpi.cs3733.c20.teamS.database.NodeData; -import edu.wpi.cs3733.c20.teamS.MainToLoginScreen; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; +import edu.wpi.cs3733.c20.teamS.utilities.rx.DisposableSelector; +import edu.wpi.cs3733.c20.teamS.utilities.rx.RxAdaptors; +import javafx.application.Application; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; -import javafx.scene.Group; import javafx.scene.Parent; import javafx.scene.Scene; -import javafx.scene.control.*; +import javafx.scene.control.Label; +import javafx.scene.control.RadioButton; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.ToggleGroup; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyCodeCombination; +import javafx.scene.input.KeyCombination; import javafx.scene.layout.VBox; -import javafx.scene.paint.Color; -import javafx.scene.shape.Circle; -import javafx.scene.shape.Line; -import javafx.scene.shape.Polygon; -import javafx.scene.shape.StrokeType; import javafx.stage.Modality; import javafx.stage.Stage; - import java.net.URL; -import java.util.*; -import java.util.stream.Collectors; +import java.util.HashSet; +import java.util.ResourceBundle; +import java.util.Set; -public class EditScreenController implements Initializable { +public class EditScreenController extends BaseScreen implements Initializable { //region fields private Stage stage; private Employee loggedIn; - private MoveNodes moveNode = new MoveNodes(); - private MapZoomer zoomer; private FloorSelector floorSelector; private ObservableGraph graph; - private IEditingTool editingTool; + private EditableMap editableMap; + private DisposableSelector toolSelector; + private final UndoBuffer undoBuffer = new UndoBuffer(); private final DatabaseController database = new DatabaseController(); private final HitboxRepository hitboxRepo = new ResourceFolderHitboxRepository(); - private final Group group = new Group(); private final Set rooms = new HashSet<>(); - private ExportToDirectoryController exportController; - - private static Color getNodeColorNonHighlighted(NodeData node) { - return node.getNodeType().equals("ELEV") ? - Settings.get().nodeColorElevator() : - Settings.get().nodeFillColorNormal(); - } - //endregion - private static class Floor { - public final Image image; - public final JFXButton button; + private final Image Ra = new Image("images/Icons/DarkMode_Sun.png", 160, 160, false, true); + private final Image Khons = new Image("images/Icons/DarkMode_Moon.png", 160, 160, false, true); - public Floor(JFXButton button, Image image) { - this.image = image; - this.button = button; - } - public Floor(JFXButton button, String imagePath) { - this(button, new Image(imagePath)); - } - } - private class FloorSelector { - private static final String SELECTED_BUTTON_STYLE = "-fx-background-color: #f6bd38; -fx-font: 32 System;"; - private static final String UNSELECTED_BUTTON_STYLE = "-fx-background-color: #ffffff; -fx-font: 22 System;"; - private final Floor[] floors_; - private final JFXButton upButton; - private final JFXButton downButton; - private int current; - private final int lowestFloor; - private final int highestFloor; - - public FloorSelector(JFXButton upButton, JFXButton downButton, Floor... floors) { - this.upButton = upButton; - this.downButton = downButton; - this.floors_ = floors; - lowestFloor = 1; - highestFloor = floors_.length; - } + private boolean darkmode; - public int current() { - return current; - } - public void setCurrent(int floorNumber) { - for (Floor floor : floors_) { - floor.button.setStyle(UNSELECTED_BUTTON_STYLE); - } - floor(floorNumber).button.setStyle(SELECTED_BUTTON_STYLE); - this.upButton.setDisable(floorNumber == this.highestFloor); - this.downButton.setDisable(floorNumber == this.lowestFloor); - - mapImage.setImage(floor(floorNumber).image); - this.current = floorNumber; - redrawMap(); - } + //endregion - private Floor floor(int floorNumber) { - return floors_[floorNumber - 1]; - } + public EditScreenController() { + this.stage = Settings.get().getPrimaryStage(); } - /** - * - * @param stage the stage to take over - * @param employee the employee that logged in - */ - public EditScreenController(Stage stage, Employee employee) { - this.stage = stage; - this.loggedIn = employee; - } @Override public void initialize(URL location, ResourceBundle resources) { - zoomer = new MapZoomer(scrollPane); - loggedInUserLabel.setText("Welcome " + loggedIn.name() + "!"); - editPrivilegeBox.setVisible(loggedIn.accessLevel() == AccessLevel.ADMIN); + fakeInitialize(); + } - initGraph(); - initFloorSelector(); - initPathfindingAlgorithmSelector(); + public void fakeInitialize() { + loggedInUserLabel.setText("Welcome " + Settings.get().getLoggedIn().name() + "!"); + editPrivilegeBox.setVisible(Settings.get().getLoggedIn().accessLevel() == AccessLevel.ADMIN); - group.setOnMouseClicked(e -> editingTool.onMapClicked(e)); - group.setOnMouseMoved(e -> editingTool.onMouseMoved(e)); + floorSelector = createFloorSelector(); + floorSelector.setCurrent(2); - if (hitboxRepo.canLoad()) + if (hitboxRepo.canLoad()) { + rooms.clear(); rooms.addAll(hitboxRepo.load()); - editingTool = createAddRemoveNodeTool(); - exportController = new ExportToDirectoryController(directoryPathTextField, exportButton, () -> rooms); - - redrawMap(); - } - - private void initGraph() { - this.graph = new ObservableGraph(database.loadGraph()); - graph.nodeAdded().subscribe(node -> { - database.addNode(node); - redrawMap(); - }, e -> System.out.println(e.getMessage())); - graph.nodeRemoved().subscribe(e -> { - database.removeNode(e.getNodeID()); - redrawMap(); - }, e -> System.out.println(e.getMessage())); - graph.edgeAdded().subscribe(e -> { - database.addEdge(e.nodeU(), e.nodeV()); - redrawMap(); - }, e -> System.out.println(e.getMessage())); - graph.edgeRemoved().subscribe(e -> { - database.removeEdge(new EdgeData(e.nodeU(), e.nodeV()).getEdgeID()); - redrawMap(); - }, e -> System.out.println(e.getMessage())); - } - private void initFloorSelector() { - floorSelector = new FloorSelector( + } + + editableMap = new EditableMap( + database.loadGraph(), + floorSelector, rooms, + scrollPane, mapImage); + graph = editableMap.graph(); + toolSelector = new DisposableSelector<>(); + toolSelector.setCurrent(new AddEditRemoveNodeTool(undoBuffer::execute, editableMap)); + createPathfindingAlgorithmSelector(); + initEventHandlers(); + ExportToDirectoryController exportController = new ExportToDirectoryController( + directoryPathTextField, exportButton, + () -> editableMap.rooms() + ); + initUndoHotkeys(); + } + + private void initUndoHotkeys() { + KeyCombination undoCombo = new KeyCodeCombination(KeyCode.Z, KeyCombination.CONTROL_DOWN); + KeyCombination redoCombo = new KeyCodeCombination(KeyCode.Y, KeyCombination.CONTROL_DOWN); + Runnable undo = () -> { + if (undoBuffer.canUndo()) + undoBuffer.undo(); + }; + Runnable redo = () -> { + if (undoBuffer.canRedo()) + undoBuffer.redo(); + }; + RxAdaptors.propertyStream(floorButton2.sceneProperty()) + .subscribe(scene -> { + System.out.println("Scene changed"); + scene.getAccelerators().put(undoCombo, undo); + scene.getAccelerators().put(redoCombo, redo); + }); + } + + private void initEventHandlers() { + graph.nodeAdded().subscribe(database::addNode); + graph.nodeRemoved().subscribe(node -> database.removeNode(node.getNodeID())); + graph.edgeAdded().subscribe(edge -> database.addEdge(edge.nodeU(), edge.nodeV())); + graph.edgeRemoved().subscribe(edge -> database.removeEdge(new EdgeData(edge.nodeU(), edge.nodeV()).getEdgeID())); + + undoButton.setDisable(!undoBuffer.canUndo()); + undoBuffer.canUndoChanged().subscribe(huh -> undoButton.setDisable(!huh)); + + redoButton.setDisable(!undoBuffer.canRedo()); + undoBuffer.canRedoChanged().subscribe(huh -> redoButton.setDisable(!huh)); + } + + private FloorSelector createFloorSelector() { + return new FloorSelector( upButton, downButton, new Floor(floorButton1, "images/Floors/HospitalFloor1.png"), new Floor(floorButton2, "images/Floors/HospitalFloor2.png"), new Floor(floorButton3, "images/Floors/HospitalFloor3.png"), new Floor(floorButton4, "images/Floors/HospitalFloor4.png"), - new Floor(floorButton5, "images/Floors/HospitalFloor5.png") + new Floor(floorButton5, "images/Floors/HospitalFloor5.png"), + new Floor(floorButton6, "images/Floors/HospitalFloor6.png"), + new Floor(floorButton7, "images/Floors/HospitalFloor7.png") ); - floorSelector.setCurrent(2); } - private void initPathfindingAlgorithmSelector() { - PathfindingAlgorithmSelector pathfindingAlgorithmSelector = new PathfindingAlgorithmSelector( + + private PathfindingAlgorithmSelector createPathfindingAlgorithmSelector() { + return new PathfindingAlgorithmSelector( astarRadioButton, djikstraRadioButton, depthFirstRadioButton, breadthFirstRadioButton ); } //region gui components - @FXML private VBox editPrivilegeBox; - @FXML private Label loggedInUserLabel; - @FXML private ImageView mapImage; - @FXML private ScrollPane scrollPane; - @FXML private JFXButton floorButton1; - @FXML private JFXButton floorButton2; - @FXML private JFXButton floorButton3; - @FXML private JFXButton floorButton4; - @FXML private JFXButton floorButton5; - @FXML private JFXButton downButton; - @FXML private JFXButton upButton; - - @FXML private ToggleGroup pathGroup; - @FXML private JFXButton zoomInButton; - @FXML private JFXButton zoomOutButton; - - @FXML private VBox editToolFieldsVBox; - - @FXML private JFXButton editEmpButton; - - @FXML private RadioButton astarRadioButton; - @FXML private RadioButton djikstraRadioButton; - @FXML private RadioButton depthFirstRadioButton; - @FXML private RadioButton breadthFirstRadioButton; - - @FXML private JFXButton cancelEditsButton; - @FXML private JFXButton confirmEditButton; - @FXML private JFXTextField directoryPathTextField; - @FXML private JFXButton exportButton; + @FXML + private VBox editPrivilegeBox; + @FXML + private Label loggedInUserLabel; + @FXML + private ImageView mapImage; + @FXML + private ImageView darkModeImage; + @FXML + private ScrollPane scrollPane; + @FXML + private JFXButton floorButton1; + @FXML + private JFXButton floorButton2; + @FXML + private JFXButton floorButton3; + @FXML + private JFXButton floorButton4; + @FXML + private JFXButton floorButton5; + @FXML + private JFXButton floorButton6; + @FXML + private JFXButton floorButton7; + @FXML + private JFXButton downButton; + @FXML + private JFXButton upButton; + + @FXML + private ToggleGroup pathGroup; + @FXML + private JFXButton zoomInButton; + @FXML + private JFXButton zoomOutButton; + + @FXML + private VBox editToolFieldsVBox; + + @FXML + private JFXButton editEmpButton; + + @FXML + private RadioButton astarRadioButton; + @FXML + private RadioButton djikstraRadioButton; + @FXML + private RadioButton depthFirstRadioButton; + @FXML + private RadioButton breadthFirstRadioButton; + + @FXML + private JFXButton cancelEditsButton; + @FXML + private JFXButton confirmEditButton; + @FXML + private JFXTextField directoryPathTextField; + @FXML + private JFXButton exportButton; + + @FXML + private JFXButton undoButton; + @FXML + private JFXButton redoButton; //endregion //region event handlers - @FXML private void onUpClicked() { + @FXML + private void onUpClicked() { floorSelector.setCurrent(floorSelector.current() + 1); } - @FXML private void onDownClicked() { + + @FXML + private void onDownClicked() { floorSelector.setCurrent(floorSelector.current() - 1); } - @FXML private void onFloorClicked1() { + + @FXML + private void onFloorClicked1() { floorSelector.setCurrent(1); } - @FXML private void onFloorClicked2() { + + @FXML + private void onFloorClicked2() { floorSelector.setCurrent(2); } - @FXML private void onFloorClicked3() { + + @FXML + private void onFloorClicked3() { floorSelector.setCurrent(3); } - @FXML private void onFloorClicked4() { + + @FXML + private void onFloorClicked4() { floorSelector.setCurrent(4); } - @FXML private void onFloorClicked5() { + + @FXML + private void onFloorClicked5() { floorSelector.setCurrent(5); } + @FXML + private void onFloorClicked6() { + floorSelector.setCurrent(6); + } + + @FXML + private void onFloorClicked7() { + floorSelector.setCurrent(7); + } @FXML - void onEditButtonPressed(ActionEvent event) { + private void onEditButtonPressed() { EmployeeEditingScreen.showDialog(); } - @FXML private void onHelpClicked() { + @FXML + private void onHelpClicked() { try { - FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/FXML/TutorialScreen.fxml")); + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/FXML/AboutMe.fxml")); Parent root1 = (Parent) fxmlLoader.load(); Stage window = new Stage(); window.initModality(Modality.APPLICATION_MODAL); @@ -263,7 +288,9 @@ void onEditButtonPressed(ActionEvent event) { System.out.println("Can't load new window"); } } - @FXML private void onStaffClicked() { + + @FXML + private void onStaffClicked() { try { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/FXML/loginScreen.fxml")); Parent root1 = (Parent) fxmlLoader.load(); @@ -277,227 +304,134 @@ void onEditButtonPressed(ActionEvent event) { System.out.println("Can't load new window"); } } - @FXML private void onZoomInClicked() { - this.zoomer.zoomIn(); - zoomInButton.setDisable(!zoomer.canZoomIn()); - zoomOutButton.setDisable(!zoomer.canZoomOut()); - } - @FXML private void onZoomOutClicked() { - this.zoomer.zoomOut(); - zoomInButton.setDisable(!zoomer.canZoomIn()); - zoomOutButton.setDisable(!zoomer.canZoomOut()); - } - @FXML private void onNewServiceClicked() { - SelectServiceScreen.showDialog(loggedIn); - } - @FXML private void onActiveServiceClicked() { - ObservableList setOfActives = FXCollections.observableArrayList(); - DatabaseController dbc = new DatabaseController(); - Set dbData = dbc.getAllServiceRequestData(); - for(ServiceData sd : dbData){ - if(!(sd.getStatus().equals("COMPLETE"))){ - setOfActives.add(sd); - System.out.println(sd.toString()); - } - } - ActiveServiceRequestScreen.showDialog(setOfActives); + + @FXML + private void onZoomInClicked() { + editableMap.zoomIn(); + zoomInButton.setDisable(!editableMap.canZoomIn()); + zoomOutButton.setDisable(!editableMap.canZoomOut()); } - @FXML private void onAddRemoveNodeClicked() { - IEditingTool tool = createAddRemoveNodeTool(); - changeEditingTool(tool); + @FXML + private void onZoomOutClicked() { + editableMap.zoomOut(); + zoomInButton.setDisable(!editableMap.canZoomIn()); + zoomOutButton.setDisable(!editableMap.canZoomOut()); } - @FXML private void onAddRemoveEdgeClicked() { - IEditingTool tool = new AddRemoveEdgeTool(graph, () -> group); - changeEditingTool(tool); + + @FXML + private void onNewServiceClicked() { + SelectServiceScreen.showDialog(Settings.get().getLoggedIn()); } - @FXML private void onAddRemoveHitboxClicked() { - AddRemoveHitboxTool tool = new AddRemoveHitboxTool( - hitbox -> { - rooms.remove(hitbox); - redrawMap(); - }, - () -> group, - () -> floorSelector.current() - ); - tool.hitboxAdded().subscribe(hitbox -> { - rooms.add(hitbox); - redrawMap(); - }); - changeEditingTool(tool); - } - @FXML private void onMoveNodeClicked() { - changeEditingTool(new MoveNodeTool(scrollPane)); - } - @FXML private void onShowInfoClicked() { - changeEditingTool(new ShowNodeInfoTool()); - } - @FXML private void onEditRoomEntrancesClicked() { - IEditingTool tool = new EditHitboxTool( - graph.nodes(), - () -> group, - editToolFieldsVBox - ); - changeEditingTool(tool); + + @FXML + private void onActiveServiceClicked() { +// ObservableList setOfActives = FXCollections.observableArrayList(); +// DatabaseController dbc = new DatabaseController(); +// Set dbData = dbc.getAllServiceRequestData(); +// for(ServiceData sd : dbData){ +// if(!(sd.getStatus().equals("COMPLETE"))){ +// setOfActives.add(sd); +// System.out.println(sd.toString()); +// } +// } +// ActiveServiceRequestScreen.showDialog(setOfActives); + ActiveServiceRequestScreen.showDialog(); } - @FXML private void onConfirmEditClicked() { - if (hitboxRepo.canSave()) - hitboxRepo.save(rooms); + @FXML + private void onAddRemoveNodeClicked() { + toolSelector.setCurrent(new AddEditRemoveNodeTool(undoBuffer::execute, editableMap)); } - @FXML private void onCancelEditClicked() { - if (hitboxRepo.canLoad()) { - rooms.clear(); - rooms.addAll(hitboxRepo.load()); - redrawMap(); - } + + @FXML + private void onAddRemoveEdgeClicked() { + toolSelector.setCurrent(new AddRemoveEdgeTool(undoBuffer::execute, editableMap)); } - //endregion - private void changeEditingTool(IEditingTool editingTool) { - IEditingTool previous = this.editingTool; - this.editingTool = editingTool; - if (previous == null) - return; - previous.onClosed(); + @FXML + private void onAddRemoveHitboxClicked() { + toolSelector.setCurrent(new AddRemoveRoomTool(undoBuffer::execute, editableMap)); } - private IEditingTool createAddRemoveNodeTool() { - return Settings.get().useQuickNodePlacingTool() ? - new QuickAddRemoveNodeTool(graph, editToolFieldsVBox, () -> floorSelector.current()) : - new AddRemoveNodeTool(graph, () -> floorSelector.current()); + + @FXML + private void onMoveNodeClicked() { + toolSelector.setCurrent(new MoveNodeTool(undoBuffer::execute, editableMap)); } - private void redrawMap() { - double currentHval = scrollPane.getHvalue(); - double currentVval = scrollPane.getVvalue(); - moveNode.setScale(zoomer.zoomFactor()); - moveNode.setCurrent_floor(floorSelector.current()); - group.getChildren().clear(); - group.getChildren().add(mapImage); + @FXML + private void onEditRoomsClicked() { + toolSelector.setCurrent(new EditRoomTool(undoBuffer::execute, editableMap)); + } - group.getChildren().add(drawAllHitboxes()); - group.getChildren().add(drawAllEdges()); - group.getChildren().add(drawAllNodes()); + @FXML + private void onAddElevatorsClicked() { + toolSelector.setCurrent(new AddElevatorTool(undoBuffer::execute, editableMap, Settings.get().floors())); + } - scrollPane.setContent(group); + @FXML + private void onConfirmEditClicked() { + if (hitboxRepo.canSave()) + hitboxRepo.save(rooms); + } - //Keeps the zoom the same throughout each screen/floor change. - keepCurrentPosition(currentHval, currentVval, zoomer); +// @FXML +// private void onCancelEditClicked() { +// if (hitboxRepo.canLoad()) { +// rooms.clear(); +// rooms.addAll(hitboxRepo.load()); +// } +// } + @FXML + void onUndoClicked(ActionEvent event) { + undoBuffer.undo(); } - private Group drawAllNodes() { - Group group = new Group(); - Set nodes = graph.nodes().stream() - .filter(node -> node.getFloor() == floorSelector.current()) - .collect(Collectors.toSet()); - for (NodeData node : nodes) { - Circle circle = drawCircle(node); - group.getChildren().add(circle); - } - return group; - } - private Group drawAllEdges() { - Group group = new Group(); - graph.edges().stream() - .filter(edge -> { - return edge.nodeU().getFloor() == floorSelector.current() || - edge.nodeV().getFloor() == floorSelector.current(); - }) - .forEach(edge -> drawLine(group, edge.nodeU(), edge.nodeV())); - - return group; - } - private Group drawAllHitboxes() { - Group result = new Group(); - rooms.stream() - .filter(hitbox -> hitbox.floor() == floorSelector.current()) - .map(hitbox -> drawHitbox(hitbox)) - .forEach(polygon -> result.getChildren().add(polygon)); - return result; - } - - private Circle drawCircle(NodeData node) { - Circle circle = new Circle(node.getxCoordinate(), node.getyCoordinate(), 25); - circle.setStroke(Settings.get().nodeStrokeColorNormal()); - final Color normal = getNodeColorNonHighlighted(node); - final Color highlighted = Settings.get().nodeFillColorHighlight(); - circle.setFill(normal); - circle.setOnMouseEntered(e -> { - circle.setFill(highlighted); - circle.setStroke(highlighted); - circle.setStrokeWidth(3); - circle.setStrokeType(StrokeType.OUTSIDE); - }); - circle.setOnMouseExited(e -> { - circle.setFill(normal); - circle.setStroke(normal); - circle.setStrokeWidth(1); - circle.setStrokeType(StrokeType.CENTERED); - }); - - node.positionChanged().subscribe(position -> { - circle.setCenterX(position.getX()); - circle.setCenterY(position.getY()); - }); - circle.setOnMouseClicked(e -> editingTool.onNodeClicked(node, e)); - circle.setOnMouseReleased(e -> editingTool.onNodeReleased(node, e)); - circle.setOnMouseDragged(e -> editingTool.onNodeDragged(node, e)); - return circle; - } - private void drawLine(Group group, NodeData start, NodeData end) { - Line line = createEdgeLine( - start.getxCoordinate(), start.getyCoordinate(), - end.getxCoordinate(), end.getyCoordinate()); - group.getChildren().add(line); - - line.setOnMouseClicked(e -> { - EndpointPair edge = EndpointPair.unordered(start, end); - editingTool.onEdgeClicked(edge, e); - }); - start.positionChanged().subscribe(e -> updateLinePosition(line, start, end)); - end.positionChanged().subscribe(e -> updateLinePosition(line, start, end)); - } - private Polygon drawHitbox(Room room) { - Polygon result = room.toPolygon(); - result.setFill(Settings.get().editHitboxColor()); - result.setOnMouseClicked(e -> editingTool.onHitboxClicked(room, e)); - return result; - } - - /** - * Creates a line used for rendering edges. - */ - private Line createEdgeLine(double startX, double startY, double endX, double endY) { - Line line = new Line(); - line.setStartX(startX); - line.setStartY(startY); - line.setEndX(endX); - line.setEndY(endY); - final Color normal = Settings.get().editEdgeColorNormal(); - final Color highlight = Settings.get().editEdgeColorHighlight(); - line.setStroke(normal); - line.setFill(normal.deriveColor(1, 1, 1, 0.5)); - line.setStrokeWidth(Settings.get().editEdgeStrokeWidth()); - line.setOnMouseEntered(e -> line.setStroke(highlight)); - line.setOnMouseExited(e -> line.setStroke(normal)); - - return line; - } - private void updateLinePosition(Line line, NodeData start, NodeData end) { - line.setStartX(start.getxCoordinate()); - line.setStartY(start.getyCoordinate()); - line.setEndX(end.getxCoordinate()); - line.setEndY(end.getyCoordinate()); + @FXML + void onRedoClicked(ActionEvent event) { + undoBuffer.redo(); } + //endregion public void onLogOut() { - MainToLoginScreen back = new MainToLoginScreen(stage); + Settings.get().setLoggedIn(null); + MainToLoginScreen.showDialog(); + } + + @FXML + private JFXTextField timeOut; + + @FXML + private JFXButton saveTimeOut; + + @FXML + void onConfirmSaveTimeOut(ActionEvent event) { + if (timeOut.getText() != null) { + BaseScreen.puggy.changeTimeout(Integer.parseInt((timeOut.getText())) * 1000); + System.out.println("Changed Timeout to: " + Integer.parseInt(timeOut.getText()) * 1000); + } } - private void keepCurrentPosition(double hval, double vval, MapZoomer zoomer){ - zoomer.zoomSet(); - scrollPane.setHvalue(hval); - scrollPane.setVvalue(vval); + @FXML + void onDarkModeClicked() { + if (darkmode) { + Application.setUserAgentStylesheet("modena.css"); + StyleManager.getInstance().addUserAgentStylesheet("default.css"); + darkmode = false; + //set image to dark mode button + darkModeImage.setImage(Khons); + System.out.println(darkModeImage.getScene().getStylesheets()); + System.out.println("returned to light mode"); + } else { + Application.setUserAgentStylesheet("modena.css"); + StyleManager.getInstance().addUserAgentStylesheet("darkmode.css"); + darkmode = true; + //set image to light mode button + darkModeImage.setImage(Ra); + System.out.println(darkModeImage.getScene().getStylesheets()); + System.out.println("changed to dark mode"); + } } + } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/MapEditingScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/MapEditingScreen.java index db5c6c3d..4ec51f7c 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/MapEditingScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/MapEditingScreen.java @@ -1,49 +1,44 @@ package edu.wpi.cs3733.c20.teamS.Editing; + +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.database.DatabaseController; -import edu.wpi.cs3733.c20.teamS.serviceRequests.Employee; -import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; +import javafx.event.Event; import javafx.scene.Scene; -import javafx.scene.input.KeyCombination; import javafx.stage.Stage; -import java.io.IOException; -public class MapEditingScreen { - private EditScreenController ui; +public class MapEditingScreen extends BaseScreen{ private Scene scene; private Stage stage; - private Employee loggedIn; - - public MapEditingScreen(Stage stage, Employee employee) { - this.loggedIn = employee; + public MapEditingScreen() { DatabaseController dbc = new DatabaseController(); dbc.autoCommit(false); - this.stage = stage; - - FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/UI_employee.fxml")); - loader.setControllerFactory(c -> { - this.ui = new EditScreenController(stage, loggedIn); - return this.ui; - }); - try { - Parent root = loader.load(); + this.stage = Settings.get().getPrimaryStage(); + this.scene = this.stage.getScene(); - this.scene = new Scene(root); + if(this.scene == null){ + this.scene = new Scene(Settings.get().getEmployeeRoot()); } - catch (IOException ex) { - throw new RuntimeException(ex); + else { + this.scene.setRoot(Settings.get().getEmployeeRoot()); } this.show(); - stage.setFullScreen(true); } public void show() { stage.setScene(scene); - stage.setMaximized(true); + //stage.setMaximized(true); //stage.initStyle(StageStyle.UNDECORATED); + //Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); + Settings.get().getEditScreenController().fakeInitialize(); stage.show(); } + + public static void showDialog(){ + new MapEditingScreen(); + } } \ No newline at end of file diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/MoveNodes.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/MoveNodes.java deleted file mode 100644 index 898db36f..00000000 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/MoveNodes.java +++ /dev/null @@ -1,113 +0,0 @@ -package edu.wpi.cs3733.c20.teamS.Editing; - -import edu.wpi.cs3733.c20.teamS.database.DatabaseController; -import edu.wpi.cs3733.c20.teamS.database.NodeData; -import javafx.event.EventHandler; -import javafx.scene.Group; -import javafx.scene.Node; -import javafx.scene.input.MouseEvent; -import org.apache.derby.iapi.db.Database; - -import java.util.Set; - -class MoveNodes { - private int current_floor; - - private double mouseX; - private double mouseY; - - private double moveX; - private double moveY; - - private Group group; - private Double scale; - - public MoveNodes() {} - - public void setGroup(Group group) { - this.group = group; - } - - public void setScale(double scale) { - this.scale = scale; - } - - public void setCurrent_floor(int current_floor) {this.current_floor = current_floor;} - - public EventHandler getOnMousePressedEventHandler() { - return onMousePressedEventHandler; - } - - public EventHandler getOnMouseDraggedEventHandler() { - return onMouseDraggedEventHandler; - } - - public EventHandler getOnMouseDragReleasedEventHandler() { - return onMouseDragReleasedEventHandler; - } - - private EventHandler onMousePressedEventHandler = new EventHandler() { - - public void handle(MouseEvent event) { - - // left mouse button => dragging - if( !event.isPrimaryButtonDown()) - return; - - mouseX = event.getSceneX(); - mouseY = event.getSceneY(); - - Node node = (Node) event.getSource(); - - moveX = node.getTranslateX(); - moveY = node.getTranslateY(); - } - - }; - - private EventHandler onMouseDraggedEventHandler = new EventHandler() { - public void handle(MouseEvent event) { - - // left mouse button => dragging - if( !event.isPrimaryButtonDown()) - return; - - Node node = (Node) event.getSource(); - - node.setTranslateX(moveX + (( event.getSceneX() - mouseX) / scale)); - node.setTranslateY(moveY + (( event.getSceneY() - mouseY) / scale)); - - event.consume(); - - } - }; - - private EventHandler onMouseDragReleasedEventHandler = new EventHandler() { - public void handle(MouseEvent event) { - NodeData data = findNearestNode(event.getX(), event.getY()); - DatabaseController dbc = new DatabaseController(); - dbc.removeNode(data.getNodeID()); - data.setxCoordinate(data.getxCoordinate() + (moveX + (( event.getSceneX() - mouseX) / scale))); - data.setyCoordinate(data.getyCoordinate() + (moveY + (( event.getSceneY() - mouseY) / scale))); - dbc.addNode(data); - } - }; - - private NodeData findNearestNode(double x, double y) { - NodeData nearest = new NodeData(); - double distance = 200; - - DatabaseController dbc = new DatabaseController(); - Set nd = dbc.getAllNodes(); - - for(NodeData temp : nd) { - if(temp.getFloor() == current_floor) { - if (Math.sqrt(Math.pow((x - temp.getxCoordinate()), 2) + Math.pow((y - temp.getyCoordinate()), 2)) < distance) { - distance = Math.sqrt(Math.pow((x - temp.getxCoordinate()), 2) + Math.pow((y - temp.getyCoordinate()), 2)); - nearest = temp; - } - } - } - return nearest; - } -} \ No newline at end of file diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/NodeEditScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/NodeEditScreen.java index 98365e64..e7d6ca97 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/NodeEditScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/NodeEditScreen.java @@ -1,15 +1,18 @@ package edu.wpi.cs3733.c20.teamS.Editing; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; import edu.wpi.cs3733.c20.teamS.database.NodeData; import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; +import javafx.stage.StageStyle; import java.io.IOException; @@ -20,6 +23,9 @@ public class NodeEditScreen { private NodeEditScreen(Stage stage) { this.stage = stage; + this.stage.setAlwaysOnTop(true); + this.stage.initStyle(StageStyle.UNDECORATED); + FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/NodeEditScreen.fxml")); loader.setControllerFactory(c -> ui = new NodeEditController()); try { @@ -32,6 +38,8 @@ private NodeEditScreen(Stage stage) { } private void show() { stage.setScene(scene); + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); stage.show(); } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/ObservableGraph.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/ObservableGraph.java similarity index 83% rename from src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/ObservableGraph.java rename to src/main/java/edu/wpi/cs3733/c20/teamS/Editing/ObservableGraph.java index 884ab8e7..0c6a140a 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/ObservableGraph.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/ObservableGraph.java @@ -1,10 +1,8 @@ -package edu.wpi.cs3733.c20.teamS.Editing.tools; +package edu.wpi.cs3733.c20.teamS.Editing; import com.google.common.graph.EndpointPair; +import com.google.common.graph.GraphBuilder; import com.google.common.graph.MutableGraph; -import edu.wpi.cs3733.c20.teamS.ThrowHelper; -import edu.wpi.cs3733.c20.teamS.database.DatabaseController; -import edu.wpi.cs3733.c20.teamS.database.EdgeData; import edu.wpi.cs3733.c20.teamS.database.NodeData; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; @@ -12,6 +10,9 @@ import java.util.Collections; import java.util.Set; +/** + * An observable undirected mutable graph that allows self-loops. + */ public final class ObservableGraph { private final MutableGraph graph; @@ -20,10 +21,8 @@ public final class ObservableGraph { private final PublishSubject> edgeAdded = PublishSubject.create(); private final PublishSubject> edgeRemoved = PublishSubject.create(); - public ObservableGraph(MutableGraph graph) { - if (graph == null) ThrowHelper.illegalNull("graph"); - - this.graph = graph; + public ObservableGraph() { + this.graph = GraphBuilder.undirected().allowsSelfLoops(true).build(); } public boolean addNode(NodeData node) { @@ -33,10 +32,13 @@ public boolean addNode(NodeData node) { return true; } public boolean removeNode(NodeData node) { - if (!graph.removeNode(node)) + if (!graph.nodes().contains(node)) return false; - + Set friends = graph.adjacentNodes(node); + graph.removeNode(node); nodeRemoved.onNext(node); + for (NodeData friend : friends) + edgeRemoved.onNext(EndpointPair.unordered(node, friend)); return true; } public boolean putEdge(NodeData start, NodeData end) { diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/PartitionedParent.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/PartitionedParent.java new file mode 100644 index 00000000..8645b844 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/PartitionedParent.java @@ -0,0 +1,92 @@ +package edu.wpi.cs3733.c20.teamS.Editing; + +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import javafx.scene.Group; +import javafx.scene.Node; +import javafx.scene.Parent; + +import java.util.*; + +/** + * Groups child controls into partitions child controls based on the value of a key. + * + * @param + * @param + */ +public class PartitionedParent extends Parent { + private final Map> partitions = new HashMap<>(); + private final Map childPartitionMap = new HashMap<>(); + + public void putChild(TKey key, TChild child) { + if (key == null) ThrowHelper.illegalNull("partition"); + if (child == null) ThrowHelper.illegalNull("child"); + + removeChild(child); + + Partition partition = partitions.computeIfAbsent( + key, k -> { + Group group = new Group(); + getChildren().add(group); + return new Partition<>(k, group, new HashSet<>()); + } + ); + childPartitionMap.put(child, key); + partition.mutableChildren.add(child); + partition.group.getChildren().add(child); + } + public boolean removeChild(TChild child) { + if (!childPartitionMap.containsKey(child)) + return false; + + TKey key = childPartitionMap.get(child); + Partition partition = partitions.get(key); + partition.group.getChildren().remove(child); + partition.mutableChildren.remove(child); + childPartitionMap.remove(child); + + return true; + } + public Collection> partitions() { + return partitions.values(); + } + public void showOnly(TKey key) { + partitions().forEach(partition -> partition.group.setVisible(Objects.equals(partition.key(), key))); + } + public boolean containsKey(TKey key) { + return partitions.containsKey(key); + } + public Partition get(TKey key) { + return partitions.get(key); + } + public Set keys() { + return partitions.keySet(); + } + + public static final class Partition { + private final TKey key; + private final Group group; + private final Set mutableChildren; + private final Set readOnlyChildren; + + Partition(TKey key, Group group, Set children) { + if (key == null) ThrowHelper.illegalNull("key"); + if (group == null) ThrowHelper.illegalNull("group"); + if (children == null) ThrowHelper.illegalNull("children"); + + this.key = key; + this.group = group; + this.mutableChildren = children; + this.readOnlyChildren = Collections.unmodifiableSet(children); + } + + public TKey key() { + return key; + } + public Group group() { + return group; + } + public Set children() { + return readOnlyChildren; + } + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/RoomEditController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/RoomEditController.java new file mode 100644 index 00000000..6b7561ca --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/RoomEditController.java @@ -0,0 +1,60 @@ +package edu.wpi.cs3733.c20.teamS.Editing; + +import com.jfoenix.controls.JFXTextArea; +import com.jfoenix.controls.JFXTextField; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; + +import java.net.URL; +import java.util.ResourceBundle; + +public final class RoomEditController implements Initializable { + private final PublishSubject okClicked = PublishSubject.create(); + private final PublishSubject cancelClicked = PublishSubject.create(); + + public RoomEditController() { + + } + @Override public void initialize(URL location, ResourceBundle resources) { + + } + + public String name() { + return nameTextField.getText(); + } + public void setName(String value) { + nameTextField.setText(value); + } + public String description() { + return descriptionTextArea.getText(); + } + public void setDescription(String value) { + descriptionTextArea.setText(value); + } + public String iconPath() { + return iconPathTextField.getText(); + } + public void setIconPath(String value) { + iconPathTextField.setText(value); + } + public Observable okClicked() { + return okClicked; + } + public Observable cancelClicked() { + return cancelClicked; + } + + //region UI controls + @FXML private JFXTextField nameTextField; + @FXML private JFXTextArea descriptionTextArea; + @FXML private JFXTextField iconPathTextField; + @FXML private void onCancelClicked() { + cancelClicked.onNext(new Object()); + } + @FXML private void onOKClicked() { + okClicked.onNext(new Object()); + } + //endregion +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/RoomEditScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/RoomEditScreen.java new file mode 100644 index 00000000..40574ebd --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/RoomEditScreen.java @@ -0,0 +1,73 @@ +package edu.wpi.cs3733.c20.teamS.Editing; + +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.app.DialogEvent; +import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Stage; +import javafx.stage.StageStyle; + +import java.io.IOException; + +public final class RoomEditScreen { + private final Stage stage; + private final Scene scene; + private RoomEditController ui; + + private RoomEditScreen(Stage stage) { + if (stage == null) ThrowHelper.illegalNull("stage"); + + this.stage = stage; + this.stage.setAlwaysOnTop(true); + this.stage.initStyle(StageStyle.UNDECORATED); + + FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/RoomEditScreen.fxml")); + loader.setControllerFactory(c -> ui = new RoomEditController()); + try { + Parent root = loader.load(); + scene = new Scene(root); + } + catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + private void show() { + stage.setScene(scene); + Settings.openWindows.add(stage); + BaseScreen.puggy.register(scene, Event.ANY); + stage.show(); + } + + public static Observable> showDialog(Stage stage, Room room) { + if (room == null) ThrowHelper.illegalNull("room"); + + PublishSubject> subject = PublishSubject.create(); + RoomEditScreen screen = new RoomEditScreen(stage); + screen.ui.setName(room.name()); + screen.ui.setDescription(room.description()); + screen.ui.setIconPath(room.icon()); + screen.ui.okClicked() + .subscribe(o -> { + room.setName(screen.ui.name()); + room.setDescription(screen.ui.description()); + room.setIcon(screen.ui.iconPath()); + stage.close(); + subject.onNext(DialogEvent.ok(room)); + }); + screen.ui.cancelClicked().subscribe(o -> { + stage.close(); + subject.onNext(DialogEvent.cancel()); + }); + screen.show(); + + return subject; + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/events/EdgeClickedEvent.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/events/EdgeClickedEvent.java new file mode 100644 index 00000000..e7f46737 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/events/EdgeClickedEvent.java @@ -0,0 +1,25 @@ +package edu.wpi.cs3733.c20.teamS.Editing.events; + +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.EdgeVm; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import javafx.scene.input.MouseEvent; + +public class EdgeClickedEvent { + private final EdgeVm edge; + private final MouseEvent event; + + public EdgeClickedEvent(EdgeVm edge, MouseEvent event) { + if (edge == null) ThrowHelper.illegalNull("edge"); + if (event == null) ThrowHelper.illegalNull("event"); + + this.edge = edge; + this.event = event; + } + + public EdgeVm edge() { + return edge; + } + public MouseEvent event() { + return event; + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/events/NodeClickedEvent.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/events/NodeClickedEvent.java new file mode 100644 index 00000000..a9f7f588 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/events/NodeClickedEvent.java @@ -0,0 +1,44 @@ +package edu.wpi.cs3733.c20.teamS.Editing.events; + +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.NodeVm; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Vector2; +import javafx.geometry.Point2D; +import javafx.scene.input.MouseEvent; + +/** + * Event data for when a node is clicked by the mouse. + */ +public class NodeClickedEvent { + private final NodeVm node; + private final MouseEvent event; + private Vector2 parentPosition = null; + + public NodeClickedEvent(NodeVm node, MouseEvent event) { + if (node == null) ThrowHelper.illegalNull("node"); + if (event == null) ThrowHelper.illegalNull("event"); + + this.node = node; + this.event = event; + } + + public NodeVm node() { + return node; + } + public MouseEvent event() { + return event; + } + + /** + * Gets the mouse position in parent coordinates. + * @return The mouse position in parent coordinates. + */ + public Vector2 parentPosition() { + if (parentPosition == null) { + Point2D point = node.localToParent(event.getX(), event.getY()); + parentPosition = new Vector2(point.getX(), point.getY()); + } + + return parentPosition; + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/events/RoomClickedEvent.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/events/RoomClickedEvent.java new file mode 100644 index 00000000..11b43c08 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/events/RoomClickedEvent.java @@ -0,0 +1,25 @@ +package edu.wpi.cs3733.c20.teamS.Editing.events; + +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.RoomVm; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import javafx.scene.input.MouseEvent; + +public class RoomClickedEvent { + private final RoomVm room; + private final MouseEvent event; + + public RoomClickedEvent(RoomVm room, MouseEvent event) { + if (room == null) ThrowHelper.illegalNull("room"); + if (event == null) ThrowHelper.illegalNull("event"); + + this.room = room; + this.event = event; + } + + public RoomVm room() { + return room; + } + public MouseEvent event() { + return event; + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddEditRemoveNodeTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddEditRemoveNodeTool.java new file mode 100644 index 00000000..5af09680 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddEditRemoveNodeTool.java @@ -0,0 +1,258 @@ +package edu.wpi.cs3733.c20.teamS.Editing.tools; + +import com.google.common.graph.EndpointPair; +import edu.wpi.cs3733.c20.teamS.Editing.NodeEditScreen; +import edu.wpi.cs3733.c20.teamS.Editing.events.EdgeClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.events.NodeClickedEvent; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.app.DialogResult; +import edu.wpi.cs3733.c20.teamS.database.NodeData; +import edu.wpi.cs3733.c20.teamS.utilities.rx.DisposableBase; +import edu.wpi.cs3733.c20.teamS.utilities.rx.DisposableSelector; +import io.reactivex.rxjava3.disposables.Disposable; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.stage.Stage; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +public final class AddEditRemoveNodeTool extends EditingTool { + private final IEditableMap map; + private final DisposableSelector state = new DisposableSelector<>(); + private String previousNodeType = "HALL"; + private String previousShortName = "NA"; + private String previousLongName = "Unnamed"; + + public AddEditRemoveNodeTool(Consumer mementoRunner, IEditableMap map) { + super(mementoRunner); + + if (map == null) ThrowHelper.illegalNull("map"); + + this.map = map; + state.setCurrent(new StandbyState()); + + addAllSubs( + map.mapClicked().subscribe(e -> state.current().onMapClicked(e)), + map.nodeClicked().subscribe(e -> state.current().onNodeClicked(e)), + map.edgeClicked().subscribe(e -> state.current().onEdgeClicked(e)) + ); + } + + private static abstract class State extends DisposableBase { + public void onNodeClicked(NodeClickedEvent data) {} + public void onMapClicked(MouseEvent event) {} + public void onEdgeClicked(EdgeClickedEvent data) {} + @Override protected void onDispose() { } + } + + private final class StandbyState extends State { + @Override public void onNodeClicked(NodeClickedEvent event) { + switch (event.event().getButton()) { + case PRIMARY: + state.setCurrent(new ShowEditNodeDialogState(event.node().node())); + break; + case SECONDARY: + Memento action = createRemoveNodeMemento(event); + execute(action); + break; + } + } + @Override public void onMapClicked(MouseEvent event) { + if (event.getButton() != MouseButton.PRIMARY) + return; + + state.setCurrent(new ShowNewNodeDialogState(event.getX(), event.getY())); + } + @Override public void onEdgeClicked(EdgeClickedEvent data) { + if (data.event().getButton() != MouseButton.PRIMARY) + return; + + double x = data.event().getX(); + double y = data.event().getY(); + + state.setCurrent(new ShowNewNodeSplitEdgeDialogState(x, y, data.edge().edge())); + } + + private Memento createRemoveNodeMemento(NodeClickedEvent event) { + return new Memento() { + private final NodeData node = event.node().node(); + private final Set friends = map.graph().inner().adjacentNodes(node); + + @Override public void execute() { + map.removeNode(node); + } + @Override public void undo() { + map.addNode(node); + for (NodeData friend : friends) + map.putEdge(node, friend); + } + }; + } + } + + private final class ShowNewNodeDialogState extends State { + private final Stage stage; + private final Disposable dialogSubscription; + + public ShowNewNodeDialogState(double x, double y) { + stage = new Stage(); + dialogSubscription = showDialog(x, y); + } + + @Override protected void onDispose() { + dialogSubscription.dispose(); + stage.close(); + } + + private Disposable showDialog(double x, double y) { + return NodeEditScreen.showDialog( + stage, previousNodeType, + previousShortName, + previousLongName + ).subscribe(e -> { + if (e.result() == DialogResult.OK) { + e.value().setBuilding("Faulkner"); + e.value().setxCoordinate(x); + e.value().setyCoordinate(y); + e.value().setFloor(map.selectedFloor()); + + execute( + () -> map.addNode(e.value()), + () -> map.removeNode(e.value()) + ); + + previousNodeType = e.value().getNodeType(); + previousShortName = e.value().getShortName(); + previousLongName = e.value().getLongName(); + } + + state.setCurrent(new StandbyState()); + }); + } + } + + private final class ShowNewNodeSplitEdgeDialogState extends State { + private final Stage stage; + private final Disposable dialogSubscription; + + public ShowNewNodeSplitEdgeDialogState(double x, double y, EndpointPair edge) { + stage = new Stage(); + dialogSubscription = showDialog(x, y, edge); + } + + @Override protected void onDispose() { + dialogSubscription.dispose(); + stage.close(); + } + + private Disposable showDialog(double x, double y, EndpointPair edge) { + return NodeEditScreen.showDialog( + stage, previousNodeType, + previousShortName, + previousLongName + ).subscribe(e -> { + if (e.result() == DialogResult.OK) { + NodeData node = e.value(); + node.setBuilding("Faulkner"); + node.setxCoordinate(x); + node.setyCoordinate(y); + node.setFloor(map.selectedFloor()); + + execute( + () -> { + map.addNode(node); + map.putEdge(edge.nodeU(), node); + map.putEdge(node, edge.nodeV()); + map.removeEdge(edge); + }, + () -> { + map.removeEdge(edge.nodeU(), node); + map.removeEdge(node, edge.nodeV()); + map.putEdge(edge); + map.removeNode(node); + } + ); + } + + state.setCurrent(new StandbyState()); + }); + } + } + + private final class ShowEditNodeDialogState extends State { + private final Stage stage; + private final Disposable dialogSubscription; + + public ShowEditNodeDialogState(NodeData node) { + if (node == null) ThrowHelper.illegalNull("node"); + + stage = new Stage(); + dialogSubscription = showDialog(node); + } + + @Override protected void onDispose() { + dialogSubscription.dispose(); + stage.close(); + } + + private Disposable showDialog(NodeData node) { + NodeState before = new NodeState(node); + return NodeEditScreen.showDialog(stage, node) + .subscribe(e -> { + if (e.result() == DialogResult.OK) { + NodeState after = new NodeState(e.value()); + Memento memento = Memento.create( + () -> {}, + () -> before.setNodeFromState(node), + () -> after.setNodeFromState(node) + ); + execute(memento); + } + state.setCurrent(new StandbyState()); + }); + } + + private class NodeState { + private final Map fieldValues = new HashMap<>(); + + public NodeState(NodeData node) { + try { + for (Field field : getMutableInstanceFields()) { + field.setAccessible(true); + fieldValues.put(field.getName(), field.get(node)); + } + } + catch (IllegalAccessException ex) { + throw new RuntimeException("Illegal read-access of field on NodeData using reflection.", ex); + } + } + + public void setNodeFromState(NodeData node) { + try { + Field[] fields = node.getClass().getDeclaredFields(); + for (Field field : getMutableInstanceFields()) { + field.setAccessible(true); + String name = field.getName(); + assert fieldValues.containsKey(name) : "Field map doesn't contain '" + name + "' field."; + Object value = fieldValues.get(name); + field.set(node, value); + } + } + catch (IllegalAccessException ex) { + throw new RuntimeException("Illegal write-access of field on NodeData using reflection.", ex); + } + } + + private List getMutableInstanceFields() { + return Arrays.stream(NodeData.class.getDeclaredFields()) + .filter(field -> !Modifier.isStatic(field.getModifiers())) + .filter(field -> !Modifier.isFinal(field.getModifiers())) + .collect(Collectors.toList()); + } + } + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddElevatorTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddElevatorTool.java new file mode 100644 index 00000000..d4f44537 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddElevatorTool.java @@ -0,0 +1,72 @@ +package edu.wpi.cs3733.c20.teamS.Editing.tools; + +import edu.wpi.cs3733.c20.teamS.Editing.events.NodeClickedEvent; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.database.NodeData; + +import java.util.function.Consumer; + +public final class AddElevatorTool extends EditingTool { + private final IEditableMap map; + private final int topFloor; + + public AddElevatorTool(Consumer mementoRunner, IEditableMap map, int topFloor) { + super(mementoRunner); + if (map == null) ThrowHelper.illegalNull("map"); + + this.map = map; + this.topFloor = topFloor; + + addAllSubs( + map.nodeClicked().subscribe(this::onNodeClicked) + ); + } + + private void onNodeClicked(NodeClickedEvent data) { + NodeData base = data.node().node(); + int newFloor = 0; + switch (data.event().getButton()) { + case PRIMARY: + newFloor = base.getFloor() + 1; + break; + case SECONDARY: + newFloor = base.getFloor() - 1; + break; + default: + return; + } + if (!isFloorInRange(newFloor)) + return; + + NodeData top = createElevatorNode(base, newFloor); + + execute( + () -> { + map.addNode(top); + map.putEdge(base, top); + }, + () -> { + map.removeEdge(base, top); + map.removeNode(top); + } + ); + map.setSelectedFloor(newFloor); + } + + private boolean isFloorInRange(int floor) { + return floor >= 1 && floor <= topFloor; + } + private NodeData createElevatorNode(NodeData base, int newFloor) { + assert base != null : "'base' is null."; + NodeData result = new NodeData(); + result.setFloor(newFloor); + result.setNodeType("ELEV"); + + result.setPosition(base.getxCoordinate(), base.getyCoordinate()); + result.setBuilding(base.getBuilding()); + result.setShortName(base.getShortName()); + result.setLongName(base.getLongName()); + + return result; + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveEdgeTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveEdgeTool.java index 9f4b16e8..3e14301d 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveEdgeTool.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveEdgeTool.java @@ -1,116 +1,100 @@ package edu.wpi.cs3733.c20.teamS.Editing.tools; -import com.google.common.graph.EndpointPair; -import com.sun.scenario.effect.impl.state.MotionBlurState; +import edu.wpi.cs3733.c20.teamS.Editing.events.EdgeClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.events.NodeClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.PlaceEdgeVm; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.database.NodeData; -import javafx.scene.Group; +import edu.wpi.cs3733.c20.teamS.utilities.rx.DisposableBase; +import edu.wpi.cs3733.c20.teamS.utilities.rx.DisposableSelector; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; -import javafx.scene.paint.Color; -import javafx.scene.shape.Line; -import org.checkerframework.framework.qual.NoDefaultQualifierForUse; -import java.util.function.Supplier; +import java.util.function.Consumer; -public final class AddRemoveEdgeTool implements IEditingTool { - private final ObservableGraph graph; - public final Supplier groupSupplier; - private State state; +public final class AddRemoveEdgeTool extends EditingTool { + private final IEditableMap map; + private final DisposableSelector state = new DisposableSelector<>(); - public AddRemoveEdgeTool(ObservableGraph graph, Supplier groupSupplier) { - this.graph = graph; - this.groupSupplier = groupSupplier; - this.state = new StandbyState(); - } + public AddRemoveEdgeTool(Consumer mementoRunner, IEditableMap map) { + super(mementoRunner); - @Override - public void onNodeClicked(NodeData node, MouseEvent event) { - state.onNodeClicked(node, event); - } - @Override - public void onEdgeClicked(EndpointPair edge, MouseEvent event) { - state.onEdgeClicked(edge, event); + if (map == null) ThrowHelper.illegalNull("map"); + + this.map = map; + state.setCurrent(new StandbyState()); + + addAllSubs( + map.nodeClicked().subscribe(e -> state.current().onNodeClicked(e)), + map.edgeClicked().subscribe(e -> state.current().onEdgeClicked(e)), + map.mouseMoved().subscribe(e -> state.current().onMouseMoved(e)) + ); } - @Override - public void onMouseMoved(MouseEvent event) { - state.onMouseMoved(event); + @Override protected void onDispose() { + state.current().dispose(); } - private abstract class State { - public void onNodeClicked(NodeData node, MouseEvent event) {} - public void onEdgeClicked(EndpointPair edge, MouseEvent event) {} + private static abstract class State extends DisposableBase { + public abstract void onNodeClicked(NodeClickedEvent data); + public abstract void onEdgeClicked(EdgeClickedEvent data); public void onMouseMoved(MouseEvent event) {} + @Override protected void onDispose() {} } private final class StandbyState extends State { - @Override - public void onNodeClicked(NodeData node, MouseEvent event) { - if (event.getButton() != MouseButton.PRIMARY) + @Override public void onNodeClicked(NodeClickedEvent data) { + if (data.event().getButton() != MouseButton.PRIMARY) return; - state = new StartNodeSelectedState(node); + state.setCurrent(new StartPlacedState(data.node().node())); } - - @Override - public void onEdgeClicked(EndpointPair edge, MouseEvent event) { - if (event.getButton() != MouseButton.SECONDARY) + @Override public void onEdgeClicked(EdgeClickedEvent data) { + if (data.event().getButton() != MouseButton.SECONDARY) return; - assert edge.nodeU() != null : "nodeU is null"; - assert edge.nodeV() != null : "nodeV is null"; - - graph.removeEdge(edge.nodeU(), edge.nodeV()); + Memento action = Memento.create( + () -> map.removeEdge(data.edge().start(), data.edge().end()), + () -> map.putEdge(data.edge().start(), data.edge().end()) + ); + execute(action); } } - - private final class StartNodeSelectedState extends State { + private final class StartPlacedState extends State { private final NodeData start; - private final Line edgeDisplay; - private static final double LINE_WIDTH = 5.0; + private final PlaceEdgeVm vm; - public StartNodeSelectedState(NodeData start) { - assert start != null : "start was null."; + public StartPlacedState(NodeData start) { this.start = start; - edgeDisplay = new Line(); - edgeDisplay.setStartX(start.getxCoordinate()); - edgeDisplay.setStartY(start.getyCoordinate()); - edgeDisplay.setEndX(start.getxCoordinate()); - edgeDisplay.setEndY(start.getyCoordinate()); - edgeDisplay.setStrokeWidth(LINE_WIDTH); - edgeDisplay.setFill(Color.BLUE); - edgeDisplay.setMouseTransparent(true); - groupSupplier.get().getChildren().add(edgeDisplay); - } - - @Override - public void onNodeClicked(NodeData node, MouseEvent event) { - if (event.getButton() != MouseButton.PRIMARY) - return; - if (graph.inner().adjacentNodes(node).contains(start)) - return; - - graph.putEdge(start, node); - switchToStandbyState(); + vm = new PlaceEdgeVm(start.getxCoordinate(), start.getyCoordinate()); + map.addWidget(vm); } - @Override - public void onEdgeClicked(EndpointPair edge, MouseEvent event) { - if (event.getButton() != MouseButton.SECONDARY) - return; - - switchToStandbyState(); + @Override public void onNodeClicked(NodeClickedEvent data) { + switch (data.event().getButton()) { + case SECONDARY: + state.setCurrent(new StandbyState()); + return; + case PRIMARY: + if (!data.node().node().equals(start)) { + NodeData end = data.node().node(); + execute( + () -> map.putEdge(start, end), + () -> map.removeEdge(start, end) + ); + } + map.removeWidget(vm); + state.setCurrent(new StandbyState()); + return; + default: + } } - - @Override - public void onMouseMoved(MouseEvent event) { - edgeDisplay.setEndX(event.getX()); - edgeDisplay.setEndY(event.getY()); + @Override protected void onDispose() { + map.removeWidget(vm); } - - private void switchToStandbyState() { - groupSupplier.get().getChildren().remove(edgeDisplay); - state = new StandbyState(); + @Override public void onEdgeClicked(EdgeClickedEvent data) { } + @Override public void onMouseMoved(MouseEvent event) { + vm.setEnd(event.getX(), event.getY()); } } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveHitboxTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveHitboxTool.java deleted file mode 100644 index de5e24bd..00000000 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveHitboxTool.java +++ /dev/null @@ -1,198 +0,0 @@ -package edu.wpi.cs3733.c20.teamS.Editing.tools; - -import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; -import edu.wpi.cs3733.c20.teamS.utilities.Vector2; -import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.subjects.PublishSubject; -import javafx.scene.Group; -import javafx.scene.input.MouseButton; -import javafx.scene.input.MouseEvent; -import javafx.scene.paint.Color; -import javafx.scene.shape.Circle; -import javafx.scene.shape.Polygon; - -import java.util.ArrayList; -import java.util.function.Consumer; -import java.util.function.IntSupplier; -import java.util.function.Supplier; - -public class AddRemoveHitboxTool implements IEditingTool { - private final PublishSubject hitboxAdded = PublishSubject.create(); - private final Consumer hitboxRemover; - private final Supplier groupSupplier; - private final IntSupplier floorSupplier; - private State state = new StandbyState(); - - /** - * @param hitboxRemover Function to delete a hitbox. - * @param groupSupplier Function to supply the group to draw in. - * @param floorSupplier Function to supply the current floor. - */ - public AddRemoveHitboxTool( - Consumer hitboxRemover, - Supplier groupSupplier, - IntSupplier floorSupplier) { - - this.hitboxRemover = hitboxRemover; - this.groupSupplier = groupSupplier; - this.floorSupplier = floorSupplier; - } - - public Observable hitboxAdded() { - return hitboxAdded; - } - - @Override public void onMapClicked(MouseEvent event) { - state.onMapClicked(event); - } - @Override public void onMouseMoved(MouseEvent event) { - state.onMouseMoved(event.getX(), event.getY()); - } - @Override public void onHitboxClicked(Room room, MouseEvent event) { - state.onHitboxClicked(room, event); - } - - @Override - public void onClosed() { - state.onClosed(); - } - - private abstract static class State { - public void onMapClicked(MouseEvent event) {} - public void onMouseMoved(double x, double y) {} - - public void onHitboxClicked(Room room, MouseEvent event) {} - - public void onClosed() {} - } - private final class StandbyState extends State { - @Override - public void onMapClicked(MouseEvent event) { - if (event.getButton() != MouseButton.PRIMARY) - return; - state = new ChainingState(event.getX(), event.getY()); - } - - @Override - public void onHitboxClicked(Room room, MouseEvent event) { - if (event.getButton() != MouseButton.SECONDARY) - return; - - hitboxRemover.accept(room); - } - } - private final class ChainingState extends State { - private final ArrayList handles = new ArrayList<>(); - private final Room room; - private final Polygon displayPolygon; - private final double radius = 7; - private final Color vertexColor = Color.BLUEVIOLET.deriveColor( - 1, 1, 1, .9); - private final Color polygonColor = Color.BLUE.deriveColor( - 1, 1, 1, .45); - - public ChainingState(double x, double y) { - room = new Room(floorSupplier.getAsInt()); - displayPolygon = new Polygon(); - displayPolygon.setFill(polygonColor); - - addVertex(x, y); - // We need to add the first vertex twice, since the last vertex will always be - // "floating" with the mouse cursor. - addVertex(x, y); - - groupSupplier.get().getChildren().add(displayPolygon); - } - - @Override - public void onClosed() { - Group group = groupSupplier.get(); - group.getChildren().removeAll(handles); - group.getChildren().remove(displayPolygon); - } - - @Override - public void onMapClicked(MouseEvent event) { - switch (event.getButton()) { - case PRIMARY: - setLastVertex(event.getX(), event.getY()); - addVertex(event.getX(), event.getY()); - break; - case SECONDARY: - switchToStandbyState(); - break; - default: - break; - } - } - private void onHandleClicked(Circle handle, MouseEvent event) { - switch (event.getButton()) { - case PRIMARY: - event.consume(); - hitboxAdded.onNext(room); - switchToStandbyState(); - break; - case SECONDARY: - switchToStandbyState(); - break; - default: - break; - } - } - @Override - public void onMouseMoved(double x, double y) { - setLastVertex(x, y); - } - - private void switchToStandbyState() { - state = new StandbyState(); - Group group = groupSupplier.get(); - group.getChildren().removeAll(handles); - group.getChildren().remove(displayPolygon); - } - - /** - * Gets the handle that is following the mouse cursor. - */ - private Circle cursorFollowingHandle() { - return handles.get(handles.size() - 1); - } - private void addVertex(double x, double y) { - Circle lastHandle = getLastHandle(); - if (lastHandle != null) - lastHandle.setVisible(true); - - Circle handle = createHandle(x, y); - handle.setVisible(false); - handles.add(handle); - room.vertices().add(new Vector2(x, y)); - displayPolygon.getPoints().addAll(x, y); - groupSupplier.get().getChildren().add(handle); - } - private Circle getLastHandle() { - if (handles.isEmpty()) - return null; - return handles.get(handles.size() - 1); - } - private Circle createHandle(double x, double y) { - Circle handle = new Circle(); - handle.setCenterX(x); - handle.setCenterY(y); - handle.setRadius(radius); - handle.setFill(vertexColor); - handle.setOnMouseClicked(e -> onHandleClicked(handle, e)); - return handle; - } - private void setLastVertex(double x, double y) { - room.setLastVertex(x, y); - - Circle handle = cursorFollowingHandle(); - handle.setCenterX(x); - handle.setCenterY(y); - - int size = displayPolygon.getPoints().size(); - displayPolygon.getPoints().set(size - 2, x); - displayPolygon.getPoints().set(size - 1, y); - } - } -} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveNodeTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveNodeTool.java deleted file mode 100644 index 2612e34b..00000000 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveNodeTool.java +++ /dev/null @@ -1,60 +0,0 @@ -package edu.wpi.cs3733.c20.teamS.Editing.tools; - -import edu.wpi.cs3733.c20.teamS.Editing.NodeEditScreen; -import edu.wpi.cs3733.c20.teamS.app.DialogResult; -import edu.wpi.cs3733.c20.teamS.database.DatabaseController; -import edu.wpi.cs3733.c20.teamS.database.NodeData; -import javafx.scene.input.MouseButton; -import javafx.scene.input.MouseEvent; -import javafx.stage.Stage; - -import java.util.Optional; -import java.util.function.Supplier; - -public final class AddRemoveNodeTool implements IEditingTool { - private final ObservableGraph graph; - private final Supplier currentFloorSupplier; - private String previousNodeType = "HALL"; - private String previousShortName = "NA"; - private String previousLongName = "Unnamed"; - - public AddRemoveNodeTool(ObservableGraph graph, Supplier currentfloorSupplier) { - this.graph = graph; - this.currentFloorSupplier = currentfloorSupplier; - } - - @Override - public void onNodeClicked(NodeData node, MouseEvent event) { - if (event.getButton() != MouseButton.SECONDARY) - return; - - graph.removeNode(node); - } - - @Override - public void onMapClicked(MouseEvent event) { - if (event.getButton() != MouseButton.PRIMARY) - return; - - Stage stage = new Stage(); - NodeEditScreen.showDialog( - stage, previousNodeType, - previousShortName, - previousLongName - ) - .subscribe(e -> { - if (e.result() == DialogResult.OK) { - e.value().setBuilding("Faulkner"); - e.value().setxCoordinate(event.getX()); - e.value().setyCoordinate(event.getY()); - e.value().setFloor(currentFloorSupplier.get()); - graph.addNode(e.value()); - - previousNodeType = e.value().getNodeType(); - previousShortName = e.value().getShortName(); - previousLongName = e.value().getLongName(); - } - stage.close(); - }); - } -} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveRoomTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveRoomTool.java new file mode 100644 index 00000000..d26beeb7 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/AddRemoveRoomTool.java @@ -0,0 +1,138 @@ +package edu.wpi.cs3733.c20.teamS.Editing.tools; + +import edu.wpi.cs3733.c20.teamS.Editing.events.RoomClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.PlaceVertexHandleVm; +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.PreviewRoomVm; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Vector2; +import edu.wpi.cs3733.c20.teamS.utilities.rx.DisposableBase; +import edu.wpi.cs3733.c20.teamS.utilities.rx.DisposableSelector; +import edu.wpi.cs3733.c20.teamS.utilities.rx.RxAdaptors; +import javafx.scene.Node; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; + +import java.util.Stack; +import java.util.function.Consumer; + +public final class AddRemoveRoomTool extends EditingTool { + private final IEditableMap map; + private final DisposableSelector state = new DisposableSelector<>(); + + public AddRemoveRoomTool(Consumer mementoRunner, IEditableMap map) { + super(mementoRunner); + + if (map == null) ThrowHelper.illegalNull("map"); + + this.map = map; + state.setCurrent(new StandbyState()); + addAllSubs( + map.mapClicked().subscribe(e -> state.current().onMapClicked(e)), + map.mouseMoved().subscribe(e -> state.current().onMouseMoved(e)), + map.roomClicked().subscribe(e -> state.current().onRoomClicked(e)) + ); + } + + @Override protected final void onDispose() { + state.current().dispose(); + } + + private static abstract class State extends DisposableBase { + public void onMapClicked(MouseEvent event) {} + public void onMouseMoved(MouseEvent event) {} + public void onRoomClicked(RoomClickedEvent data) {} + protected void onDispose() {} + } + + private final class StandbyState extends State { + @Override public void onMapClicked(MouseEvent event) { + if (event.getButton() != MouseButton.PRIMARY) + return; + + state.setCurrent(new PlacingState(event.getX(), event.getY())); + } + @Override public void onRoomClicked(RoomClickedEvent data) { + if (data.event().getButton() != MouseButton.SECONDARY) + return; + + execute( + () -> map.removeRoom(data.room().room()), + () -> map.addRoom(data.room().room()) + ); + } + } + + private final class PlacingState extends State { + private final PreviewRoomVm preview; + private final Room room = new Room(); + private final Stack handles = new Stack<>(); + + public PlacingState(double x, double y) { + preview = new PreviewRoomVm(x, y); + pushVertex(x, y); + pushVertex(x, y); + map.addWidget(preview); + room.setFloor(map.selectedFloor()); + } + + @Override public void onMapClicked(MouseEvent event) { + switch (event.getButton()) { + case PRIMARY: + preview.setLastVertex(event.getX(), event.getY()); + preview.pushVertex(event.getX(), event.getY()); + pushVertex(event.getX(), event.getY()); + break; + case SECONDARY: + state.setCurrent(new StandbyState()); + break; + default: + break; + } + } + @Override public void onMouseMoved(MouseEvent event) { + preview.setLastVertex(event.getX(), event.getY()); + room.setLastVertex(event.getX(), event.getY()); + if (!handles.isEmpty()) { + handles.peek().setTranslateX(event.getX()); + handles.peek().setTranslateY(event.getY()); + } + } + @Override protected void onDispose() { + map.removeWidget(preview); + for (Node node : handles) + map.removeWidget(node); + } + + private void pushVertex(double x, double y) { + room.vertices().add(new Vector2(x, y)); + + if (!handles.isEmpty()) { + handles.peek().setMouseTransparent(false); + handles.peek().setVisible(true); + handles.peek().setTranslateX(x); + handles.peek().setTranslateY(y); + } + + PlaceVertexHandleVm handle = new PlaceVertexHandleVm(x, y); + handle.setMouseTransparent(true); + handle.setVisible(false); + RxAdaptors.eventStream(handle::setOnMouseClicked).subscribe(e -> onVertexHandleClicked(handle, e)); + handles.push(handle); + map.addWidget(handle); + } + private void onVertexHandleClicked(PlaceVertexHandleVm handle, MouseEvent event) { + if (event.getButton() != MouseButton.PRIMARY) + return; + + event.consume(); + + execute( + () -> map.addRoom(room), + () -> map.removeRoom(room) + ); + + state.setCurrent(new StandbyState()); + } + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/EditHitboxTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/EditHitboxTool.java deleted file mode 100644 index 1943cd23..00000000 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/EditHitboxTool.java +++ /dev/null @@ -1,180 +0,0 @@ -package edu.wpi.cs3733.c20.teamS.Editing.tools; - -import com.jfoenix.controls.JFXTextField; -import edu.wpi.cs3733.c20.teamS.ThrowHelper; -import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; -import edu.wpi.cs3733.c20.teamS.database.NodeData; -import edu.wpi.cs3733.c20.teamS.widgets.AutoComplete; -import io.reactivex.rxjava3.core.Observable; -import javafx.geometry.Insets; -import javafx.scene.Group; -import javafx.scene.control.Label; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.VBox; -import javafx.scene.paint.Color; -import javafx.scene.shape.Circle; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -public class EditHitboxTool implements IEditingTool { - private static class UI { - private final JFXTextField nameField; - private final VBox vbox; - - public UI(VBox vbox) { - this.vbox = vbox; - Label label = new Label(); - label.setText("Hitbox name: "); - Insets insets = new Insets(8, 5, 8, 5); - label.setPadding(insets); - nameField = new JFXTextField(); - nameField.setPadding(insets); - vbox.getChildren().addAll(label, nameField); - } - - public String name() { - return nameField.getText(); - } - public void setName(String value) { - nameField.setText(value); - } - public Observable nameChanged() { - return AutoComplete.propertyStream(nameField.textProperty()); - } - public void clear() { - vbox.getChildren().clear(); - } - } - - private final Map nodeLookup; - private final Supplier groupSupplier; - private final UI ui; - private State state; - - public EditHitboxTool( - Set nodes, - Supplier groupSupplier, - VBox vbox - ) { - if (nodes == null) ThrowHelper.illegalNull("nodes"); - if (groupSupplier == null) ThrowHelper.illegalNull("groupSupplier"); - if (vbox == null) ThrowHelper.illegalNull("vbox"); - - this.nodeLookup = nodes.stream() - .collect(Collectors.toMap(node -> node.getNodeID(), node -> node)); - this.groupSupplier = groupSupplier; - ui = new UI(vbox); - ui.nameChanged().subscribe(name -> state.onNameChanged(name)); - - state = new StandbyState(); - } - - @Override - public void onHitboxClicked(Room room, MouseEvent event) { - state.onHitboxClicked(room, event); - } - - @Override - public void onNodeClicked(NodeData node, MouseEvent event) { - state.onNodeClicked(node, event); - } - - @Override - public void onClosed() { - state.onClosed(); - ui.clear(); - } - - private abstract static class State { - public abstract void onHitboxClicked(Room room, MouseEvent event); - public abstract void onNodeClicked(NodeData node, MouseEvent event); - public abstract void onClosed(); - public abstract void onNameChanged(String name); - } - - private final class StandbyState extends State { - @Override public void onHitboxClicked(Room room, MouseEvent event) { - state = new EditingHitboxState(room); - } - @Override public void onNodeClicked(NodeData node, MouseEvent event) {} - @Override public void onClosed() {} - @Override public void onNameChanged(String name) {} - } - private final class EditingHitboxState extends State { - private final Room room; - private final Map highlighters; - private final Group group; - private boolean respondToNameChanged = true; - - public EditingHitboxState(Room room) { - if (room == null) ThrowHelper.illegalNull("hitbox"); - - this.room = room; - ui.setName(room.name()); - highlighters = new HashMap<>(); - group = groupSupplier.get(); - room.touchingNodes().removeIf(id -> !nodeLookup.containsKey(id)); - room.touchingNodes().stream() - .map(nodeLookup::get) - .forEach(this::addNodeHighlighter); - } - - @Override public void onHitboxClicked(Room room, MouseEvent event) { - if (room == this.room) - return; - group.getChildren().removeAll(highlighters.values()); - highlighters.clear(); - respondToNameChanged = false; - state = new EditingHitboxState(room); - } - @Override public void onNodeClicked(NodeData node, MouseEvent event) { - switch (event.getButton()) { - case PRIMARY: - if (room.touchingNodes().add(node.getNodeID())) - addNodeHighlighter(node); - break; - case SECONDARY: - removeNode(node); - break; - default: - break; - } - } - @Override public void onClosed() { - group.getChildren().removeAll(highlighters.values()); - } - @Override public void onNameChanged(String name) { - if (!respondToNameChanged) - return; - room.setName(name); - } - - private Circle createNodeHighlighter(NodeData node) { - Circle circle = new Circle(); - circle.setFill(Color.LIME); - circle.setRadius(20); - circle.setCenterX(node.getxCoordinate()); - circle.setCenterY(node.getyCoordinate()); - circle.setMouseTransparent(true); - return circle; - } - - private void addNodeHighlighter(NodeData node) { - Circle circle = createNodeHighlighter(node); - group.getChildren().add(circle); - highlighters.put(node, circle); - } - - private void removeNode(NodeData node) { - if (!room.touchingNodes().remove(node.getNodeID())) - return; - Circle circle = highlighters.get(node); - group.getChildren().remove(circle); - highlighters.remove(node); - } - } -} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/EditRoomTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/EditRoomTool.java new file mode 100644 index 00000000..034092c3 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/EditRoomTool.java @@ -0,0 +1,199 @@ +package edu.wpi.cs3733.c20.teamS.Editing.tools; + +import edu.wpi.cs3733.c20.teamS.Editing.RoomEditScreen; +import edu.wpi.cs3733.c20.teamS.Editing.events.NodeClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.events.RoomClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.EditRoomVertexVm; +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.NodeVm; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import edu.wpi.cs3733.c20.teamS.database.NodeData; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Vector2; +import edu.wpi.cs3733.c20.teamS.utilities.rx.DisposableBase; +import edu.wpi.cs3733.c20.teamS.utilities.rx.DisposableSelector; +import io.reactivex.rxjava3.disposables.Disposable; +import javafx.scene.input.MouseButton; +import javafx.stage.Stage; + +import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +public final class EditRoomTool extends EditingTool { + private final IEditableMap map; + private final DisposableSelector state = new DisposableSelector<>(); + private final Map nodeLookup; + + public EditRoomTool(Consumer mementoRunner, IEditableMap map) { + super(mementoRunner); + if (map == null) ThrowHelper.illegalNull("map"); + + this.map = map; + state.setCurrent(new StandbyState()); + nodeLookup = map.graph().nodes().stream() + .collect(Collectors.toMap(NodeData::getNodeID, node -> node)); + + addAllSubs( + map.roomClicked().subscribe(e -> state.current().onRoomClicked(e)), + map.nodeClicked().subscribe(e -> state.current().onNodeClicked(e)) + ); + } + + @Override + protected void onDispose() { + state.current().dispose(); + } + + private static abstract class State extends DisposableBase { + public void onRoomClicked(RoomClickedEvent data) {} + public void onNodeClicked(NodeClickedEvent data) {} + @Override protected void onDispose() {} + } + + private final class StandbyState extends State { + @Override public void onRoomClicked(RoomClickedEvent data) { + if (data.event().getButton() != MouseButton.PRIMARY) + return; + state.setCurrent(new RoomSelectedState(data.room().room())); + } + } + + private final class RoomSelectedState extends State { + private final Room room; + private final List handles = new ArrayList<>(); + private final Set touchingNodeVms = new HashSet<>(); + private HandleState dragState; + + public RoomSelectedState(Room room) { + this.room = room; + dragState = new NotDraggingState(); + + initRoomVertexHandles(room); + initTouchingNodes(room); + } + + private void initTouchingNodes(Room room) { + room.touchingNodes().removeIf(id -> { + boolean remove = !nodeLookup.containsKey(id); + if (remove) { + System.err.println("Missing touching node '" + id + "' on room '" + room.name() + "'."); + } + else + addTouchingNode(nodeLookup.get(id)); + return remove; + }); + } + private void initRoomVertexHandles(Room room) { + for (int index = 0; index < room.vertices().size(); index++) { + EditRoomVertexVm handle = new EditRoomVertexVm(room, index); + handle.dragged().subscribe(v -> dragState.onDrag(handle, v)); + handle.released().subscribe(v -> dragState.onRelease(handle, v)); + handles.add(handle); + map.addWidget(handle); + } + } + + @Override protected void onDispose() { + handles.forEach(map::removeWidget); + touchingNodeVms.forEach(vm -> vm.setSelected(false)); + } + + @Override public void onRoomClicked(RoomClickedEvent data) { + switch (data.event().getButton()) { + case PRIMARY: + this.dispose(); + state.setCurrent(() -> new RoomSelectedState(data.room().room())); + break; + case SECONDARY: + state.setCurrent(new ShowDialogState(data.room().room())); + break; + } + } + @Override public void onNodeClicked(NodeClickedEvent data) { + switch (data.event().getButton()) { + case PRIMARY: + addTouchingNode(data.node().node()); + break; + case SECONDARY: + removeTouchingNode(data.node().node()); + break; + } + } + + private void addTouchingNode(NodeData node) { + NodeVm vm = map.getNodeViewModel(node); + vm.setSelected(true); + touchingNodeVms.add(vm); + room.touchingNodes().add(node.getNodeID()); + } + private void removeTouchingNode(NodeData node) { + NodeVm vm = map.getNodeViewModel(node); + vm.setSelected(false); + touchingNodeVms.remove(vm); + room.touchingNodes().remove(node.getNodeID()); + } + + private abstract class HandleState { + public void onDrag(EditRoomVertexVm handle, Vector2 mouse) {} + public void onRelease(EditRoomVertexVm handle, Vector2 mouse) {} + } + + private final class NotDraggingState extends HandleState { + @Override public void onDrag(EditRoomVertexVm handle, Vector2 mouse) { + dragState = new DraggingState(handle, mouse); + } + } + + private final class DraggingState extends HandleState { + private final Vector2 start; + + public DraggingState(EditRoomVertexVm handle, Vector2 mouse) { + map.setPannable(false); + this.start = handle.room().vertices().get(handle.vertexIndex()); + onDrag(handle, mouse); + } + + @Override public void onDrag(EditRoomVertexVm handle, Vector2 mouse) { + handle.setTranslateX(mouse.x()); + handle.setTranslateY(mouse.y()); + handle.room().vertices().set(handle.vertexIndex(), mouse); + } + @Override public void onRelease(EditRoomVertexVm handle, Vector2 mouse) { + map.setPannable(true); + + Room room = handle.room(); + int index = handle.vertexIndex(); + execute( + () -> room.vertices().set(index, mouse), + () -> room.vertices().set(index, start) + ); + + dragState = new NotDraggingState(); + } + } + } + + private final class ShowDialogState extends State { + private final Stage stage; + private final Room room; + private final Disposable subscription; + + public ShowDialogState(Room room) { + if (room == null) ThrowHelper.illegalNull("room"); + + this.room = room; + stage = new Stage(); + subscription = showDialog(); + } + + @Override protected void onDispose() { + stage.close(); + subscription.dispose(); + } + + private Disposable showDialog() { + return RoomEditScreen.showDialog(stage, room) + .subscribe(e -> state.setCurrent(new RoomSelectedState(room))); + } + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/EditableMap.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/EditableMap.java new file mode 100644 index 00000000..5f07fd0e --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/EditableMap.java @@ -0,0 +1,388 @@ +package edu.wpi.cs3733.c20.teamS.Editing.tools; + +import com.google.common.graph.EndpointPair; +import com.google.common.graph.MutableGraph; +import edu.wpi.cs3733.c20.teamS.Editing.ObservableGraph; +import edu.wpi.cs3733.c20.teamS.Editing.PartitionedParent; +import edu.wpi.cs3733.c20.teamS.Editing.events.EdgeClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.events.NodeClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.events.RoomClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.EdgeVm; +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.NodeVm; +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.RoomVm; +import edu.wpi.cs3733.c20.teamS.Settings; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import edu.wpi.cs3733.c20.teamS.database.NodeData; +import edu.wpi.cs3733.c20.teamS.pathDisplaying.FloorSelector; +import edu.wpi.cs3733.c20.teamS.pathDisplaying.MapZoomer; +import edu.wpi.cs3733.c20.teamS.utilities.rx.ReactiveProperty; +import edu.wpi.cs3733.c20.teamS.utilities.rx.RxAdaptors; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.scene.Group; +import javafx.scene.Node; +import javafx.scene.control.ScrollPane; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; + +import java.util.*; +import java.util.stream.Stream; + +public class EditableMap implements IEditableMap { + private final ObservableGraph graph; + private final ScrollPane scrollPane; + private final ImageView mapImage; + private final MapZoomer zoomer; + private final FloorSelector floorSelector; + private final Map nodeLookup = new HashMap<>(); + private final Map, EdgeVm> edgeLookup = new HashMap<>(); + private final Map roomLookup = new HashMap<>(); + private final Group rootGroup; + private final PartitionedParent nodePartition = new PartitionedParent<>(); + private final PartitionedParent edgePartition = new PartitionedParent<>(); + private final PartitionedParent roomPartition = new PartitionedParent<>(); + private final PartitionedParent auxiliaryPartition = new PartitionedParent<>(); + + private final ReactiveProperty showNodes = new ReactiveProperty<>(true); + private final ReactiveProperty showEdges = new ReactiveProperty<>(true); + private final ReactiveProperty showRooms = new ReactiveProperty<>(true); + + + private final PublishSubject nodeClicked = PublishSubject.create(); + private final PublishSubject nodeDragged = PublishSubject.create(); + private final PublishSubject nodeReleased = PublishSubject.create(); + private final PublishSubject edgeClicked = PublishSubject.create(); + private final PublishSubject roomClicked = PublishSubject.create(); + private final Observable mapClicked; + private final Observable mouseMoved; + + public EditableMap( + MutableGraph graph, + FloorSelector floorSelector, Collection rooms, + ScrollPane scrollPane, ImageView mapImage + ) { + if (graph == null) ThrowHelper.illegalNull("graph"); + if (floorSelector == null) ThrowHelper.illegalNull("floorSelector"); + if (rooms == null) ThrowHelper.illegalNull("rooms"); + + this.floorSelector = floorSelector; + this.scrollPane = scrollPane; + zoomer = new MapZoomer(this.scrollPane, Settings.get().minZoomStage(), Settings.get().maxZoomStage()); + this.rootGroup = new Group(); + this.mapImage = mapImage; + this.graph = createGraph(); + graph.nodes().forEach(this.graph::addNode); + graph.edges().forEach(edge -> this.graph.putEdge(edge.nodeU(), edge.nodeV())); + rooms.forEach(this::onRoomAdded); + + mapClicked = RxAdaptors.eventStream(this.rootGroup::setOnMouseClicked); + mouseMoved = RxAdaptors.eventStream(this.rootGroup::setOnMouseMoved); + + floorSelector.currentChanged() + .subscribe(n -> { + mapImage.setImage(floorSelector.floor(n).image); + nodePartition.showOnly(n); + edgePartition.showOnly(n); + roomPartition.showOnly(n); + auxiliaryPartition.showOnly(n); + updateZoom(); + }); + floorSelector.setCurrent(1); + + updateZoom(); + while (zoomer.canZoomOut()) + zoomer.zoomOut(); + } + + public ObservableGraph graph() { + return graph; + } + + public boolean canZoomIn() { + return zoomer.canZoomIn(); + } + public boolean canZoomOut() { + return zoomer.canZoomOut(); + } + public void zoomIn() { + zoomer.zoomIn(); + updateZoom(); + } + public void zoomOut() { + zoomer.zoomOut(); + updateZoom(); + } + + /** + * Adds the specified UI widget to the root Parent object of the EditableMap. The added node will + * be automatically hidden when the selected floor changes. + * @param node The ui node to add. + */ + public void addWidget(Node node) { + auxiliaryPartition.putChild(selectedFloor(), node); + } + + /** + * Removes the specified UI widget from the root parent object of the EditableMap. + * @param node The ui node to remove. + */ + public void removeWidget(Node node) { + auxiliaryPartition.removeChild(node); + } + + public boolean addNode(NodeData node) { + return graph.addNode(node); + } + public boolean removeNode(NodeData node) { + return graph.removeNode(node); + } + public boolean putEdge(NodeData nodeU, NodeData nodeV) { + return graph.putEdge(nodeU, nodeV); + } + public boolean removeEdge(NodeData nodeU, NodeData nodeV) { + return graph.removeEdge(nodeU, nodeV); + } + public boolean addRoom(Room room) { + if (roomLookup.containsKey(room)) + return false; + onRoomAdded(room); + return true; + } + public boolean removeRoom(Room room) { + if (!roomLookup.containsKey(room)) + return false; + onRoomRemoved(room); + return true; + } + @Override public int selectedFloor() { + return floorSelector.current(); + } + @Override public void setSelectedFloor(int value) { + floorSelector.setCurrent(value); + } + public boolean isPannable() { + return scrollPane.isPannable(); + } + public void setPannable(boolean value) { + scrollPane.setPannable(value); + } + public Set rooms() { + return roomLookup.keySet(); + } + + /** + * Gets the view model used to render the specified node. + * @param node The node to get the view-model for. + * @return The view model that is rendering the specified node. + */ + @Override + public NodeVm getNodeViewModel(NodeData node) { + if (node == null) ThrowHelper.illegalNull("node"); + + return nodeLookup.get(node); + } + + /** + * Gets the view model for the specified edge. + * @param edge The edge to get the view model for. + * @return The view model that is used to render the edge. + */ + @Override + public EdgeVm getEdgeViewModel(EndpointPair edge) { + if (edge == null) ThrowHelper.illegalNull("edge"); + + return edgeLookup.get(edge); + } + /** + * Gets the view model for the specified room. + * @param room The room to get the view model for. + * @return The view model that is used to render the specified room. + */ + @Override + public RoomVm getRoomViewModel(Room room) { + if (room == null) ThrowHelper.illegalNull("room"); + + return roomLookup.get(room); + } + + public Set getNodesOnFloor(int floor) { + if (!nodePartition.containsKey(floor)) + return Collections.emptySet(); + return nodePartition.get(floor).children(); + } + public Set getEdgesOnFloor(int floor) { + if (!edgePartition.containsKey(floor)) + return Collections.emptySet(); + return edgePartition.get(floor).children(); + } + public Set getRoomsOnFloor(int floor) { + if (!roomPartition.containsKey(floor)) + return Collections.emptySet(); + return roomPartition.get(floor).children(); + } + @Override public Stream nodeViewModels() { + return nodePartition.partitions().stream() + .map(partition -> partition.children()) + .flatMap(Collection::stream); + } + @Override public Stream edgeViewModels() { + return edgePartition.partitions().stream() + .map(partition -> partition.children()) + .flatMap(Collection::stream); + } + @Override public Stream roomViewModels() { + return roomPartition.partitions().stream() + .map(partition -> partition.children()) + .flatMap(Collection::stream); + } + @Override public void setNodesVisible(boolean value) { + nodePartition.partitions() + .forEach(partition -> partition.group().setVisible(value)); + } + @Override public void setNodesVisible(boolean value, int floor) { + if (!nodePartition.containsKey(floor)) + return; + nodePartition.get(floor).group().setVisible(value); + } + @Override public void setEdgesVisible(boolean value) { + edgePartition.partitions() + .forEach(partition -> partition.group().setVisible(value)); + } + @Override public void setEdgesVisible(boolean value, int floor) { + if (!edgePartition.containsKey(floor)) + return; + edgePartition.get(floor).group().setVisible(value); + } + @Override public void setRoomsVisible(boolean value) { + roomPartition.partitions() + .forEach(partition -> partition.group().setVisible(value)); + } + @Override public void setRoomsVisible(boolean value, int floor) { + if (!roomPartition.containsKey(floor)) + return; + roomPartition.get(floor).group().setVisible(value); + } + + public Observable nodeClicked() { + return nodeClicked; + } + public Observable nodeDragged() { + return nodeDragged; + } + public Observable nodeReleased() { + return nodeReleased; + } + public Observable edgeClicked() { + return edgeClicked; + } + public Observable roomClicked() { + return roomClicked; + } + public Observable mapClicked() { + return mapClicked; + } + public Observable mouseMoved() { + return mouseMoved; + } + + private void updateZoom() { + double hval = scrollPane.getHvalue(); + double vval = scrollPane.getVvalue(); + + rootGroup.getChildren().clear(); + rootGroup.getChildren().add(mapImage); + rootGroup.getChildren().add(roomPartition); + rootGroup.getChildren().add(edgePartition); + rootGroup.getChildren().add(nodePartition); + rootGroup.getChildren().add(auxiliaryPartition); + + scrollPane.setContent(rootGroup); + + zoomer.zoomSet(); + scrollPane.setHvalue(hval); + scrollPane.setVvalue(vval); + } + private ObservableGraph createGraph() { + ObservableGraph graph = new ObservableGraph(); + + graph.nodeAdded().subscribe(this::onNodeAdded); + graph.nodeRemoved().subscribe(this::onNodeRemoved); + graph.edgeAdded().subscribe(this::onEdgeAdded); + graph.edgeRemoved().subscribe(this::onEdgeRemoved); + + return graph; + } + private NodeVm createNodeVm(NodeData node) { + assert node != null : "node can't be null!"; + + NodeVm result = new NodeVm(node); + result.setOnMouseClicked(e -> nodeClicked.onNext(new NodeClickedEvent(result, e))); + result.setOnMouseDragged(e -> nodeDragged.onNext(new NodeClickedEvent(result, e))); + result.setOnMouseReleased(e -> nodeReleased.onNext(new NodeClickedEvent(result, e))); + + return result; + } + private EdgeVm createEdgeVm(NodeData start, NodeData end) { + assert start != null : "'start' can't be null."; + assert end != null : "'end' can't be null."; + + EdgeVm result = new EdgeVm(start, end); + result.setOnMouseClicked(e -> edgeClicked.onNext(new EdgeClickedEvent(result, e))); + + return result; + } + private RoomVm createRoomVm(Room room) { + assert room != null : "'room' can't be null."; + + RoomVm result = new RoomVm(room); + result.setOnMouseClicked(e -> roomClicked.onNext(new RoomClickedEvent(result, e))); + return result; + } + private void onNodeAdded(NodeData node) { + if (node == null) ThrowHelper.illegalNull("node"); + + assert graph.nodes().contains(node) : "graph doesn't contain added node " + node.getNodeID(); + NodeVm vm = createNodeVm(node); + nodeLookup.put(node, vm); + nodePartition.putChild(node.getFloor(), vm); + } + private void onNodeRemoved(NodeData node) { + if (node == null) ThrowHelper.illegalNull("node"); + + NodeVm remove = nodeLookup.get(node); + nodePartition.removeChild(remove); + nodeLookup.remove(node); + } + private void onEdgeAdded(EndpointPair edge) { + if (edge == null) ThrowHelper.illegalNull("edge"); + + assert graph.nodes().contains(edge.nodeU()) : "node not in graph: " + edge.nodeU().getNodeID(); + assert graph.nodes().contains(edge.nodeV()) : "node not in graph: " + edge.nodeV().getNodeID(); + + EdgeVm vm = createEdgeVm(edge.nodeU(), edge.nodeV()); + edgePartition.putChild(edge.nodeU().getFloor(), vm); + edgeLookup.put(edge, vm); + } + private void onEdgeRemoved(EndpointPair edge) { + if (edge == null) ThrowHelper.illegalNull("edge"); + + EdgeVm remove = edgeLookup.get(edge); + edgePartition.removeChild(remove); + edgeLookup.remove(edge); + } + private void onRoomAdded(Room room) { + if (room == null) ThrowHelper.illegalNull("room"); + + RoomVm vm = createRoomVm(room); + roomPartition.putChild(room.floor(), vm); + roomLookup.put(room, vm); + } + private void onRoomRemoved(Room room) { + if (room == null) ThrowHelper.illegalNull("room"); + + RoomVm remove = roomLookup.get(room); + roomPartition.removeChild(remove); + roomLookup.remove(room); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/EditingTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/EditingTool.java new file mode 100644 index 00000000..199c4a37 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/EditingTool.java @@ -0,0 +1,47 @@ +package edu.wpi.cs3733.c20.teamS.Editing.tools; + +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import io.reactivex.rxjava3.disposables.CompositeDisposable; +import io.reactivex.rxjava3.disposables.Disposable; + +import java.util.function.Consumer; + +public abstract class EditingTool implements Disposable { + private final CompositeDisposable disposables = new CompositeDisposable(); + private final Consumer mementoRunner; + + protected EditingTool(Consumer mementoRunner) { + if (mementoRunner == null) ThrowHelper.illegalNull("mementoExecutor"); + + this.mementoRunner = mementoRunner; + } + protected final void execute(Memento memento) { + mementoRunner.accept(memento); + } + protected final void execute(Runnable execute, Runnable undo) { + mementoRunner.accept(Memento.create(execute, undo)); + } + protected final void addSub(Disposable subscription) { + if (subscription == null) ThrowHelper.illegalNull("subscription"); + + disposables.add(subscription); + } + protected final void addAllSubs(Disposable... subscriptions) { + this.disposables.addAll(subscriptions); + } + + @Override public final void dispose() { + if (isDisposed()) + return; + disposables.dispose(); + onDispose(); + } + /** + * Called when the EditingTool is disposed. + */ + protected void onDispose() {} + + @Override public final boolean isDisposed() { + return disposables.isDisposed(); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/IEditableMap.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/IEditableMap.java new file mode 100644 index 00000000..8231dee6 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/IEditableMap.java @@ -0,0 +1,64 @@ +package edu.wpi.cs3733.c20.teamS.Editing.tools; + +import com.google.common.graph.EndpointPair; +import edu.wpi.cs3733.c20.teamS.Editing.ObservableGraph; +import edu.wpi.cs3733.c20.teamS.Editing.events.EdgeClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.events.NodeClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.events.RoomClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.EdgeVm; +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.NodeVm; +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.RoomVm; +import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import edu.wpi.cs3733.c20.teamS.database.NodeData; +import io.reactivex.rxjava3.core.Observable; +import javafx.scene.Node; +import javafx.scene.input.MouseEvent; + +import java.util.stream.Stream; + +public interface IEditableMap { + Stream nodeViewModels(); + Stream edgeViewModels(); + Stream roomViewModels(); + void setNodesVisible(boolean value); + void setNodesVisible(boolean value, int floor); + void setEdgesVisible(boolean value); + void setEdgesVisible(boolean value, int floor); + void setRoomsVisible(boolean value); + void setRoomsVisible(boolean value, int floor); + + Observable nodeClicked(); + Observable nodeDragged(); + Observable nodeReleased(); + Observable edgeClicked(); + Observable roomClicked(); + Observable mapClicked(); + Observable mouseMoved(); + boolean addNode(NodeData node); + boolean removeNode(NodeData node); + boolean putEdge(NodeData nodeU, NodeData nodeV); + default boolean putEdge(EndpointPair edge) { + return putEdge(edge.nodeU(), edge.nodeV()); + } + boolean removeEdge(NodeData nodeU, NodeData nodeV); + default boolean removeEdge(EndpointPair edge) { + return removeEdge(edge.nodeU(), edge.nodeV()); + } + boolean addRoom(Room room); + boolean removeRoom(Room room); + int selectedFloor(); + void addWidget(Node node); + void removeWidget(Node node); + + void setSelectedFloor(int value); + + boolean isPannable(); + void setPannable(boolean value); + ObservableGraph graph(); + NodeVm getNodeViewModel(NodeData node); + EdgeVm getEdgeViewModel(EndpointPair edge); + default EdgeVm getEdgeViewModel(NodeData nodeU, NodeData nodeV) { + return getEdgeViewModel(EndpointPair.unordered(nodeU, nodeV)); + } + RoomVm getRoomViewModel(Room room); +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/IEditingTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/IEditingTool.java deleted file mode 100644 index 0e1ecb31..00000000 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/IEditingTool.java +++ /dev/null @@ -1,18 +0,0 @@ -package edu.wpi.cs3733.c20.teamS.Editing.tools; - -import com.google.common.graph.EndpointPair; -import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; -import edu.wpi.cs3733.c20.teamS.database.NodeData; -import javafx.scene.input.MouseEvent; - -public interface IEditingTool { - default void onMapClicked(MouseEvent event) {} - default void onMouseMoved(MouseEvent event) {} - default void onNodeClicked(NodeData node, MouseEvent event) {} - default void onEdgeClicked(EndpointPair edge, MouseEvent event) {} - default void onHitboxClicked(Room room, MouseEvent event) {} - - default void onNodeDragged(NodeData node, MouseEvent e) {} - default void onNodeReleased(NodeData node, MouseEvent e) {} - default void onClosed() {} -} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/Memento.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/Memento.java new file mode 100644 index 00000000..2667e969 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/Memento.java @@ -0,0 +1,46 @@ +package edu.wpi.cs3733.c20.teamS.Editing.tools; + +import edu.wpi.cs3733.c20.teamS.ThrowHelper; + +public abstract class Memento { + public abstract void execute(); + public abstract void undo(); + public void redo() { + execute(); + } + + + public static Memento create(Runnable execute, Runnable undo, Runnable redo) { + if (execute == null) ThrowHelper.illegalNull("execute"); + if (undo == null) ThrowHelper.illegalNull("undo"); + if (redo == null) ThrowHelper.illegalNull("redo"); + + return new Memento() { + @Override public void execute() { + execute.run(); + } + @Override public void undo() { + undo.run(); + } + @Override public void redo() { + redo.run(); + } + }; + } + public static Memento create(Runnable execute, Runnable undo) { + if (execute == null) ThrowHelper.illegalNull("execute"); + if (undo == null) ThrowHelper.illegalNull("undo"); + + return new Memento() { + @Override + public void execute() { + execute.run(); + } + + @Override + public void undo() { + undo.run(); + } + }; + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/MoveNodeTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/MoveNodeTool.java index b6a36a87..b68fd79a 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/MoveNodeTool.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/MoveNodeTool.java @@ -1,25 +1,72 @@ package edu.wpi.cs3733.c20.teamS.Editing.tools; -import edu.wpi.cs3733.c20.teamS.database.NodeData; -import javafx.scene.control.ScrollPane; -import javafx.scene.input.MouseEvent; +import edu.wpi.cs3733.c20.teamS.Editing.events.NodeClickedEvent; +import edu.wpi.cs3733.c20.teamS.Editing.viewModels.NodeVm; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.utilities.rx.DisposableBase; +import edu.wpi.cs3733.c20.teamS.utilities.rx.DisposableSelector; +import java.util.function.Consumer; -public final class MoveNodeTool implements IEditingTool { - private final ScrollPane scrollPane; +public final class MoveNodeTool extends EditingTool { + private final IEditableMap map; + private final DisposableSelector state = new DisposableSelector<>(); - public MoveNodeTool(ScrollPane scrollPane) { - this.scrollPane = scrollPane; + public MoveNodeTool(Consumer mementoRunner, IEditableMap map) { + super(mementoRunner); + + if (map == null) ThrowHelper.illegalNull("map"); + + this.map = map; + + addAllSubs( + map.nodeDragged().subscribe(this::onNodeDragged), + map.nodeReleased().subscribe(this::onNodeReleased) + ); + state.setCurrent(new StandbyState()); } - @Override - public void onNodeDragged(NodeData node, MouseEvent e) { - scrollPane.setPannable(false); - node.setPosition(e.getX(), e.getY()); + private void onNodeDragged(NodeClickedEvent e) { + state.current().onNodeDragged(e); } + private void onNodeReleased(NodeClickedEvent e) { + state.current().onNodeReleased(e); + } + + private static abstract class State extends DisposableBase { + public void onNodeDragged(NodeClickedEvent data) {} + public void onNodeReleased(NodeClickedEvent data) {} + @Override protected void onDispose() {} + } + + private final class StandbyState extends State { + @Override public void onNodeDragged(NodeClickedEvent data) { + state.setCurrent(new DraggingState(data.node())); + } + } + private final class DraggingState extends State { + private final NodeVm nodeVm; + private final double startX, startY; + + public DraggingState(NodeVm nodeVm) { + this.startX = nodeVm.node().getxCoordinate(); + this.startY = nodeVm.node().getyCoordinate(); + this.nodeVm = nodeVm; + map.setPannable(false); + } - @Override - public void onNodeReleased(NodeData node, MouseEvent e) { - scrollPane.setPannable(true); + @Override public void onNodeDragged(NodeClickedEvent data) { + nodeVm.node().setPosition(data.parentPosition().x(), data.parentPosition().y()); + } + @Override public void onNodeReleased(NodeClickedEvent data) { + double x = data.parentPosition().x(); + double y = data.parentPosition().y(); + execute( + () -> data.node().node().setPosition(x, y), + () -> data.node().node().setPosition(startX, startY) + ); + map.setPannable(true); + state.setCurrent(new StandbyState()); + } } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/QuickAddRemoveNodeTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/QuickAddRemoveNodeTool.java deleted file mode 100644 index 60d080f2..00000000 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/QuickAddRemoveNodeTool.java +++ /dev/null @@ -1,133 +0,0 @@ -package edu.wpi.cs3733.c20.teamS.Editing.tools; - -import com.google.common.graph.EndpointPair; -import com.jfoenix.controls.JFXTextField; -import edu.wpi.cs3733.c20.teamS.ThrowHelper; -import edu.wpi.cs3733.c20.teamS.database.DatabaseController; -import edu.wpi.cs3733.c20.teamS.database.NodeData; -import javafx.geometry.Insets; -import javafx.scene.Node; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Label; -import javafx.scene.input.MouseButton; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.VBox; - -import java.util.List; -import java.util.function.IntSupplier; - -public class QuickAddRemoveNodeTool implements IEditingTool { - private final UI ui; - private final ObservableGraph graph; - private final IntSupplier floorSupplier; - - public QuickAddRemoveNodeTool( - ObservableGraph graph, - VBox vbox, IntSupplier floorSupplier) { - if (graph == null) ThrowHelper.illegalNull("graph"); - if (vbox == null) ThrowHelper.illegalNull("vbox"); - if (floorSupplier == null) ThrowHelper.illegalNull("floorSupplier"); - - this.graph = graph; - this.ui = new UI(vbox); - this.floorSupplier = floorSupplier; - } - - @Override - public void onMapClicked(MouseEvent event) { - if (event.getButton() != MouseButton.PRIMARY) - return; - - NodeData node = createNodeAt(event.getX(), event.getY()); - graph.addNode(node); - } - - @Override - public void onClosed() { - ui.vbox.getChildren().clear(); - } - - private NodeData createNodeAt(double x, double y) { - NodeData node = new NodeData(); - node.setFloor(floorSupplier.getAsInt()); - node.setPosition(x, y); - node.setNodeType(ui.nodeType()); - node.setBuilding("Faulkner"); - node.setLongName(ui.longName()); - node.setShortName(ui.shortName()); - return node; - } - - @Override - public void onNodeClicked(NodeData node, MouseEvent event) { - if (event.getButton() != MouseButton.SECONDARY) - return; - - graph.removeNode(node); - } - - @Override - public void onEdgeClicked(EndpointPair edge, MouseEvent event) { - if (event.getButton() != MouseButton.PRIMARY) - return; - - graph.removeEdge(edge.nodeU(), edge.nodeV()); - NodeData node = createNodeAt(event.getX(), event.getY()); - graph.addNode(node); - graph.putEdge(edge.nodeU(), node); - graph.putEdge(node, edge.nodeV()); - event.consume(); - } - - private static class UI { - private final VBox vbox; - private final ComboBox nodeTypeComboBox; - private final JFXTextField longNameTextField; - private final JFXTextField shortNameTextField; - - public UI(VBox vbox) { - this.vbox = vbox; - this.vbox.getChildren().clear(); - List controls = vbox.getChildren(); - Insets padding = new Insets(8, 5, 8, 5); - nodeTypeComboBox = new ComboBox<>(); - nodeTypeComboBox.setPadding(padding); - nodeTypeComboBox.getItems().addAll( - "HALL", "DEPT", "CONF", - "SERV", "RETL", "INFO", - "LABS", "ELEV", "STAI", "EXIT" - ); - nodeTypeComboBox.getSelectionModel().selectFirst(); - longNameTextField = new JFXTextField(); - longNameTextField.setText("Unnamed"); - longNameTextField.setPadding(padding); - shortNameTextField = new JFXTextField(); - shortNameTextField.setPadding(padding); - shortNameTextField.setText("NA"); - - controls.add(withText("Node Type:")); - controls.add(nodeTypeComboBox); - controls.add(withText("Long name: ")); - controls.add(longNameTextField); - controls.add(withText("Short name: ")); - controls.add(shortNameTextField); - } - - public String nodeType() { - return nodeTypeComboBox.getValue(); - } - public String longName() { - return longNameTextField.getText(); - } - public String shortName() { - return shortNameTextField.getText(); - } - - private Label withText(String text) { - Label result = new Label(); - result.setText(text); - result.setPadding(new Insets(8, 5, 8, 5)); - return result; - } - } -} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/ShowNodeInfoTool.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/ShowNodeInfoTool.java deleted file mode 100644 index e9646756..00000000 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/ShowNodeInfoTool.java +++ /dev/null @@ -1,18 +0,0 @@ -package edu.wpi.cs3733.c20.teamS.Editing.tools; - -import edu.wpi.cs3733.c20.teamS.Editing.NodeEditScreen; -import edu.wpi.cs3733.c20.teamS.database.NodeData; -import javafx.scene.input.MouseEvent; -import javafx.stage.Stage; - -public class ShowNodeInfoTool implements IEditingTool { - - @Override - public void onNodeClicked(NodeData node, MouseEvent event) { - Stage stage = new Stage(); - NodeEditScreen.showDialog(stage, node) - .subscribe(e -> { - stage.close(); - }); - } -} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/UndoBuffer.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/UndoBuffer.java new file mode 100644 index 00000000..273f107c --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/tools/UndoBuffer.java @@ -0,0 +1,80 @@ +package edu.wpi.cs3733.c20.teamS.Editing.tools; + +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.utilities.rx.ReactiveProperty; +import io.reactivex.rxjava3.core.Observable; + +import java.util.Stack; + +public final class UndoBuffer { + private final Stack undoStack = new Stack<>(); + private final Stack redoStack = new Stack<>(); + private ReactiveProperty canUndo = new ReactiveProperty<>(false); + private ReactiveProperty canRedo = new ReactiveProperty<>(false); + + public UndoBuffer() { + updateProperties(); + } + + /** + * Undoes the most recently-performed action. + * @throws IllegalStateException undo buffer is empty. + */ + public void undo() { + if (!canUndo.value()) + throw new IllegalStateException("Undo buffer is empty."); + + Memento memento = undoStack.pop(); + memento.undo(); + redoStack.push(memento); + + updateProperties(); + } + + /** + * Redoes the most-recently undone action. + * @throws IllegalStateException redo buffer is empty. + */ + public void redo() { + if (!canRedo.value()) + throw new IllegalStateException("Redo buffer is empty."); + + Memento memento = redoStack.pop(); + memento.redo(); + undoStack.push(memento); + + updateProperties(); + } + + /** + * Executes the specified memento, pushing it onto the undo buffer and clearing the redo buffer. + * @param memento The memento to execute. + * @throws IllegalArgumentException 'memento' is null. + */ + public void execute(Memento memento) { + if (memento == null) ThrowHelper.illegalNull("memento"); + + redoStack.clear(); + memento.execute(); + undoStack.push(memento); + + updateProperties(); + } + public boolean canUndo() { + return canUndo.value(); + } + public boolean canRedo() { + return canRedo.value(); + } + public Observable canUndoChanged() { + return canUndo.changed(); + } + public Observable canRedoChanged() { + return canRedo.changed(); + } + + private void updateProperties() { + canUndo.setValue(!undoStack.isEmpty()); + canRedo.setValue(!redoStack.isEmpty()); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/EdgeVm.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/EdgeVm.java new file mode 100644 index 00000000..7abdc4ae --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/EdgeVm.java @@ -0,0 +1,120 @@ +package edu.wpi.cs3733.c20.teamS.Editing.viewModels; + +import com.google.common.graph.EndpointPair; +import edu.wpi.cs3733.c20.teamS.Settings; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.database.NodeData; +import edu.wpi.cs3733.c20.teamS.utilities.rx.ReactiveProperty; +import javafx.scene.Parent; +import javafx.scene.paint.Color; +import javafx.scene.shape.Circle; +import javafx.scene.shape.Line; + +public final class EdgeVm extends Parent { + private final NodeData start; + private final NodeData end; + + private final Line visibleMask; + private final Circle startBall; + private final Circle endBall; + private final Line collisionMask; + private final ReactiveProperty isMouseOver = new ReactiveProperty<>(false); + private final ReactiveProperty highlightOnMouseOver = new ReactiveProperty<>(true); + private final ReactiveProperty enlargeOnMouseOver = new ReactiveProperty<>(true); + + public EdgeVm(NodeData start, NodeData end) { + if (start == null) ThrowHelper.illegalNull("start"); + if (end == null) ThrowHelper.illegalNull("end"); + + this.start = start; + this.end = end; + + visibleMask = new Line(); + updateLinePosition(visibleMask); + visibleMask.setStrokeWidth(Settings.get().editEdgeStrokeWidth()); + visibleMask.setStroke(Settings.get().editEdgeColorNormal()); + visibleMask.setMouseTransparent(true); + getChildren().add(visibleMask); + + startBall = createEndpointCircle(0, 0); + //getChildren().add(startBall); + + endBall = startBall; + + collisionMask = new Line(); + updateLinePosition(collisionMask); + collisionMask.setStroke(Color.TRANSPARENT); + collisionMask.setStrokeWidth(Settings.get().editEdgeCollisionMaskWidth()); + getChildren().add(collisionMask); + + initEventHandlers(start, end); + } + + private Circle createEndpointCircle(double x, double y) { + Circle circle = new Circle(); + circle.setCenterX(x); + circle.setCenterY(y); + circle.setStroke(Settings.get().editEdgeColorNormal()); + circle.setStroke(Settings.get().editEdgeColorNormal()); + circle.setMouseTransparent(true); + return circle; + } + private void initEventHandlers(NodeData start, NodeData end) { + start.positionChanged() + .mergeWith(end.positionChanged()) + .subscribe(e -> { + updateLinePosition(visibleMask); + updateLinePosition(collisionMask); + }); + collisionMask.setOnMouseEntered(e -> isMouseOver.setValue(true)); + collisionMask.setOnMouseExited(e -> isMouseOver.setValue(false)); + isMouseOver.changed() + .mergeWith(highlightOnMouseOver.changed()) + .subscribe(e -> updateHighlightState()); + isMouseOver.changed() + .mergeWith(enlargeOnMouseOver.changed()) + .subscribe(e -> { + double width = isMouseOver.value() && enlargeOnMouseOver.value() ? + Settings.get().editEdgeEnlargeRatio() * + Settings.get().editEdgeStrokeWidth() : + 1.0 * Settings.get().editEdgeStrokeWidth(); + visibleMask.setStrokeWidth(width); + }); + } + + public NodeData start() { + return start; + } + public NodeData end() { + return end; + } + public EndpointPair edge() { + return EndpointPair.unordered(start, end); + } + public boolean highlightOnMouseOver() { + return highlightOnMouseOver.value(); + } + public void setHighlightOnMouseOver(boolean value) { + highlightOnMouseOver.setValue(value); + } + public boolean enlargeOnMouseOver() { + return enlargeOnMouseOver.value(); + } + public void setEnlargeOnMouseOver(boolean value) { + enlargeOnMouseOver.setValue(value); + } + + private void updateHighlightState() { + Color stroke = isMouseOver.value() && highlightOnMouseOver.value() ? + Settings.get().editEdgeColorHighlight() : + Settings.get().editEdgeColorNormal(); + visibleMask.setStroke(stroke); + } + + private void updateLinePosition(Line line) { + line.setStartX(start.getxCoordinate()); + line.setStartY(start.getyCoordinate()); + line.setEndX(end.getxCoordinate()); + line.setEndY(end.getyCoordinate()); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/EditRoomVertexVm.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/EditRoomVertexVm.java new file mode 100644 index 00000000..8785a6e5 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/EditRoomVertexVm.java @@ -0,0 +1,56 @@ +package edu.wpi.cs3733.c20.teamS.Editing.viewModels; + +import edu.wpi.cs3733.c20.teamS.Settings; +import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Vector2; +import edu.wpi.cs3733.c20.teamS.utilities.rx.RxAdaptors; +import io.reactivex.rxjava3.core.Observable; +import javafx.collections.ListChangeListener; +import javafx.scene.Parent; + +public class EditRoomVertexVm extends Parent { + private final Room room; + private final int vertexIndex; + private final Observable dragged; + private final Observable released; + + public EditRoomVertexVm(Room room, int vertexIndex) { + this.room = room; + this.vertexIndex = vertexIndex; + Vector2 position = room.vertices().get(vertexIndex); + setTranslateX(position.x()); + setTranslateY(position.y()); + + HighlightCircle mask = new HighlightCircle(5, 9); + mask.setTranslateX(0); + mask.setTranslateY(0); + mask.setNormalFillColor(Settings.get().editRoomColorNormal()); + mask.setHighlightFillColor(Settings.get().editRoomColorHighlight()); + getChildren().add(mask); + + dragged = RxAdaptors.eventStream(this::setOnMouseDragged) + .map(e -> localToParent(e.getX(), e.getY())) + .map(point -> new Vector2(point.getX(), point.getY())); + released = RxAdaptors.eventStream(this::setOnMouseReleased) + .map(e -> localToParent(e.getX(), e.getY())) + .map(point -> new Vector2(point.getX(), point.getY())); + + room.vertices().addListener((ListChangeListener) change -> { + setTranslateX(room.vertices().get(vertexIndex).x()); + setTranslateY(room.vertices().get(vertexIndex).y()); + }); + } + + public Observable dragged() { + return dragged; + } + public Observable released() { + return released; + } + public Room room() { + return room; + } + public int vertexIndex() { + return vertexIndex; + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/HighlightCircle.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/HighlightCircle.java new file mode 100644 index 00000000..b4f67f1f --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/HighlightCircle.java @@ -0,0 +1,174 @@ +package edu.wpi.cs3733.c20.teamS.Editing.viewModels; + +import edu.wpi.cs3733.c20.teamS.utilities.rx.ReactiveProperty; +import javafx.scene.Parent; +import javafx.scene.paint.Color; +import javafx.scene.shape.Circle; + +/** + * Displays a circle that can be configured to highlight and enlarge on mouse-over. + */ +public class HighlightCircle extends Parent { + private static final Object UNIT = new Object(); + + private final Circle visibleMask; + private final Circle collisionMask; + private final ReactiveProperty isMouseOver = new ReactiveProperty<>(false); + private final ReactiveProperty highlightOnMouseOver = new ReactiveProperty<>(true); + private final ReactiveProperty highlightFillColor = new ReactiveProperty<>(Color.AQUA); + private final ReactiveProperty normalFillColor = new ReactiveProperty<>(Color.BLUE); + private final ReactiveProperty highlightStrokeColor = new ReactiveProperty<>(Color.AQUA); + private final ReactiveProperty normalStrokeColor = new ReactiveProperty<>(Color.BLUE); + + private final ReactiveProperty isSelected = new ReactiveProperty<>(false); + private final ReactiveProperty selectedFillColor = new ReactiveProperty<>(Color.LIME); + private final ReactiveProperty selectedStrokeColor = new ReactiveProperty<>(Color.LIME); + + private final ReactiveProperty enlargeOnMouseOver = new ReactiveProperty<>(true); + private final ReactiveProperty normalRadius = new ReactiveProperty<>(12.0); + private final ReactiveProperty highlightRadius = new ReactiveProperty<>(20.0); + private final ReactiveProperty collisionRadius = new ReactiveProperty<>(20.0); + + + public HighlightCircle(double normalRadius, double highlightRadius) { + this(); + + this.normalRadius.setValue(normalRadius); + this.highlightRadius.setValue(highlightRadius); + this.collisionRadius.setValue(highlightRadius); + } + public HighlightCircle() { + visibleMask = new Circle(); + visibleMask.setMouseTransparent(true); + getChildren().add(visibleMask); + + collisionMask = new Circle(); + collisionMask.setFill(Color.TRANSPARENT); + collisionMask.setStroke(Color.TRANSPARENT); + getChildren().add(collisionMask); + + collisionMask.setOnMouseEntered(e -> isMouseOver.setValue(true)); + collisionMask.setOnMouseExited(e -> isMouseOver.setValue(false)); + + isMouseOver.changed().map(huh -> UNIT) + .mergeWith(highlightOnMouseOver.changed()) + .mergeWith(highlightFillColor.changed()) + .mergeWith(normalFillColor.changed()) + .mergeWith(highlightStrokeColor.changed()) + .mergeWith(normalStrokeColor.changed()) + .mergeWith(isSelected.changed()) + .mergeWith(selectedFillColor.changed()) + .mergeWith(selectedStrokeColor.changed()) + .subscribe(u -> updateDisplayColor()); + + isMouseOver.changed().map(huh -> UNIT) + .mergeWith(enlargeOnMouseOver.changed()) + .mergeWith(highlightRadius.changed()) + .mergeWith(normalRadius.changed()) + .mergeWith(collisionRadius.changed()) + .subscribe(u -> updateVisibleRadius()); + + updateVisibleRadius(); + updateDisplayColor(); + } + + public boolean highlightOnMouseOver() { + return highlightOnMouseOver.value(); + } + public void setHighlightOnMouseOver(boolean value) { + highlightOnMouseOver.setValue(value); + } + public boolean enlargeOnMouseOver() { + return enlargeOnMouseOver.value(); + } + public void setEnlargeOnMouseOver(boolean value) { + enlargeOnMouseOver.setValue(value); + } + + public Color highlightFillColor() { + return highlightFillColor.value(); + } + public void setHighlightFillColor(Color value) { + highlightFillColor.setValue(value); + } + public Color normalFillColor() { + return normalFillColor.value(); + } + public void setNormalFillColor(Color value) { + normalFillColor.setValue(value); + } + public Color highlightStrokeColor() { + return highlightStrokeColor.value(); + } + public void setHighlightStrokeColor(Color value) { + highlightStrokeColor.setValue(value); + } + public Color normalStrokeColor() { + return normalStrokeColor.value(); + } + public void setNormalStrokeColor(Color value) { + normalStrokeColor.setValue(value); + } + + public double normalRadius() { + return normalRadius.value(); + } + public void setNormalRadius(double value) { + normalRadius.setValue(value); + } + public double highlightRadius() { + return highlightRadius.value(); + } + public void setHighlightRadius(double value) { + highlightRadius.setValue(value); + } + public double collisionRadius() { + return collisionRadius.value(); + } + public void setCollisionRadius(double value) { + collisionRadius.setValue(value); + } + + public boolean isSelected() { + return isSelected.value(); + } + public void setSelected(boolean value) { + isSelected.setValue(value); + } + public Color selectedFillColor() { + return selectedFillColor.value(); + } + public void setSelectedFillColor(Color value) { + selectedFillColor.setValue(value); + } + public Color selectedStrokeColor() { + return selectedStrokeColor.value(); + } + public void setSelectedStrokeColor(Color color) { + selectedStrokeColor.setValue(color); + } + + private void updateDisplayColor() { + if (isSelected.value()) { + visibleMask.setFill(selectedFillColor.value()); + visibleMask.setStroke(selectedStrokeColor.value()); + return; + } + + if (highlightOnMouseOver.value() && isMouseOver.value()) { + visibleMask.setFill(highlightFillColor.value()); + visibleMask.setStroke(highlightStrokeColor.value()); + } + else { + visibleMask.setFill(normalFillColor.value()); + visibleMask.setStroke(normalStrokeColor.value()); + } + } + private void updateVisibleRadius() { + double visibleRadius = enlargeOnMouseOver.value() && isMouseOver.value() ? + highlightRadius.value() : + normalRadius.value(); + visibleMask.setRadius(visibleRadius); + collisionMask.setRadius(collisionRadius.value()); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/NodeVm.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/NodeVm.java new file mode 100644 index 00000000..4fc5a6a5 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/NodeVm.java @@ -0,0 +1,41 @@ +package edu.wpi.cs3733.c20.teamS.Editing.viewModels; + +import edu.wpi.cs3733.c20.teamS.Settings; +import edu.wpi.cs3733.c20.teamS.database.NodeData; +import javafx.scene.Parent; + +public final class NodeVm extends Parent { + private final NodeData node; + private final HighlightCircle mask; + + public NodeVm(NodeData node) { + this.node = node; + setTranslateX(node.getxCoordinate()); + setTranslateY(node.getyCoordinate()); + + mask = new HighlightCircle(12, 20); + mask.setNormalFillColor(Settings.get().nodeFillColorNormal()); + mask.setHighlightFillColor(Settings.get().nodeFillColorHighlight()); + mask.setNormalStrokeColor(Settings.get().nodeStrokeColorNormal()); + mask.setHighlightStrokeColor(Settings.get().nodeFillColorHighlight()); + + getChildren().add(mask); + + node.positionChanged().subscribe(n -> updatePosition()); + } + + public NodeData node() { + return node; + } + public boolean isSelected() { + return mask.isSelected(); + } + public void setSelected(boolean value) { + mask.setSelected(value); + } + + private void updatePosition() { + setTranslateX(node.getxCoordinate()); + setTranslateY(node.getyCoordinate()); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/PlaceEdgeVm.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/PlaceEdgeVm.java new file mode 100644 index 00000000..8990fbbb --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/PlaceEdgeVm.java @@ -0,0 +1,32 @@ +package edu.wpi.cs3733.c20.teamS.Editing.viewModels; + +import edu.wpi.cs3733.c20.teamS.Settings; +import javafx.scene.Parent; +import javafx.scene.shape.Line; + +/** + * The preview edge that is displayed when placing an edge in the map editor. + */ +public class PlaceEdgeVm extends Parent { + private final Line line; + + public PlaceEdgeVm(double startX, double startY) { + setTranslateX(startX); + setTranslateY(startY); + + line = new Line(); + line.setStartX(0); + line.setStartY(0); + line.setEndX(0); + line.setEndY(0); + line.setStrokeWidth(Settings.get().editEdgeStrokeWidth()); + line.setStroke(Settings.get().editEdgeColorNormal()); + line.setMouseTransparent(true); + getChildren().add(line); + } + + public void setEnd(double endX, double endY) { + line.setEndX(endX - getTranslateX()); + line.setEndY(endY - getTranslateY()); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/PlaceVertexHandleVm.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/PlaceVertexHandleVm.java new file mode 100644 index 00000000..311a93f6 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/PlaceVertexHandleVm.java @@ -0,0 +1,19 @@ +package edu.wpi.cs3733.c20.teamS.Editing.viewModels; + +import edu.wpi.cs3733.c20.teamS.Settings; +import javafx.scene.Parent; + +/** + * The clickable "handle" that is displayed when placing the vertex points of a Room in the + * map editor. + */ +public class PlaceVertexHandleVm extends Parent { + public PlaceVertexHandleVm(double x, double y) { + setTranslateX(x); + setTranslateY(y); + HighlightCircle mask = new HighlightCircle(5, 8); + mask.setNormalFillColor(Settings.get().editRoomColorNormal()); + mask.setHighlightFillColor(Settings.get().editRoomColorHighlight()); + getChildren().add(mask); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/PreviewRoomVm.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/PreviewRoomVm.java new file mode 100644 index 00000000..4e0ebf52 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/PreviewRoomVm.java @@ -0,0 +1,30 @@ +package edu.wpi.cs3733.c20.teamS.Editing.viewModels; + +import edu.wpi.cs3733.c20.teamS.Settings; +import javafx.scene.Parent; +import javafx.scene.shape.Polygon; + +import java.util.List; + +public class PreviewRoomVm extends Parent { + private final Polygon previewPolygon; + + public PreviewRoomVm(double startX, double startY) { + setTranslateX(startX); + setTranslateY(startY); + previewPolygon = new Polygon(); + previewPolygon.getPoints().addAll(0.0, 0.0, 0.0, 0.0); + previewPolygon.setFill(Settings.get().editRoomColorNormal()); + getChildren().add(previewPolygon); + } + + public void setLastVertex(double x, double y) { + List points = previewPolygon.getPoints(); + int size = points.size(); + points.set(size - 2, x - getTranslateX()); + points.set(size - 1, y - getTranslateY()); + } + public void pushVertex(double x, double y) { + previewPolygon.getPoints().addAll(x - getTranslateX(), y - getTranslateY()); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/RoomVm.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/RoomVm.java new file mode 100644 index 00000000..19c23328 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Editing/viewModels/RoomVm.java @@ -0,0 +1,103 @@ +package edu.wpi.cs3733.c20.teamS.Editing.viewModels; + +import edu.wpi.cs3733.c20.teamS.Settings; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Vector2; +import edu.wpi.cs3733.c20.teamS.utilities.rx.ReactiveProperty; +import edu.wpi.cs3733.c20.teamS.utilities.rx.ReadOnlyReactiveProperty; +import edu.wpi.cs3733.c20.teamS.utilities.rx.RxAdaptors; +import javafx.scene.Parent; +import javafx.scene.control.Label; +import javafx.scene.paint.Color; +import javafx.scene.shape.Polygon; +import javafx.scene.text.Font; + +public class RoomVm extends Parent { + private final Room room; + private final Polygon mask; + private final Label nameLabel; + private final ReactiveProperty highlightOnMouseOver = new ReactiveProperty<>(true); + private final ReadOnlyReactiveProperty isMouseOver = RxAdaptors.createMouseOverStream(this); + + public RoomVm(Room room) { + if (room == null) ThrowHelper.illegalNull("room"); + + this.room = room; + mask = createPolygon(room); + nameLabel = createNameLabel(room); + + getChildren().add(mask); + getChildren().add(nameLabel); + + Vector2 centroid = room.centroid(); + setTranslateX(centroid.x()); + setTranslateY(centroid.y()); + + isMouseOver.changed() + .mergeWith(highlightOnMouseOver.changed()) + .map(e -> highlightOnMouseOver.value() && isMouseOver.value()) + .subscribe(huh -> { + Color fill = huh ? + Settings.get().editRoomColorHighlight() : + Settings.get().editRoomColorNormal(); + mask.setFill(fill); + }); + RxAdaptors.fromObservableList(room.vertices()) + .subscribe(change -> updatePolygon()); + + setNameFontSize(24); + setNameVisible(false); + } + + public Room room() { + return room; + } + public boolean highlightOnMouseOver() { + return highlightOnMouseOver.value(); + } + public void setHighlightOnMouseOver(boolean value) { + highlightOnMouseOver.setValue(value); + } + public void setNameFontSize(double value) { + Font font = new Font(nameLabel.getFont().getFamily(), value); + nameLabel.setFont(font); + } + public double nameFontSize() { + return nameLabel.getFont().getSize(); + } + public boolean isNameVisible() { + return nameLabel.isVisible(); + } + public void setNameVisible(boolean value) { + nameLabel.setVisible(value); + } + + private static Polygon createPolygon(Room room) { + Polygon result = new Polygon(); + Vector2 centroid = room.centroid(); + room.vertices().stream() + .map(vertex -> vertex.subtract(centroid)) + .forEach(local -> result.getPoints().addAll(local.x(), local.y())); + result.setFill(Settings.get().editRoomColorNormal()); + return result; + } + private void updatePolygon() { + mask.getPoints().clear(); + room.vertices().stream() + .map(vertex -> vertex.subtract(new Vector2(getTranslateX(), getTranslateY()))) + .forEach(local -> mask.getPoints().addAll(local.x(), local.y())); + } + private Label createNameLabel(Room room) { + Label result = new Label(); + result.setText(room.name()); + room.nameChanged().subscribe(result::setText); + result.setMouseTransparent(true); + RxAdaptors.propertyStream(result.boundsInParentProperty()) + .subscribe(bounds -> { + result.setTranslateX(-bounds.getWidth() / 2); + result.setTranslateY(-bounds.getHeight() / 2); + }); + return result; + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/LoginScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/LoginScreen.java index ea5d566b..13f94ad7 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/LoginScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/LoginScreen.java @@ -1,20 +1,19 @@ package edu.wpi.cs3733.c20.teamS; -import edu.wpi.cs3733.c20.teamS.Editing.MapEditingScreen; import edu.wpi.cs3733.c20.teamS.app.DialogResult; -import edu.wpi.cs3733.c20.teamS.serviceRequests.Employee; -import edu.wpi.cs3733.c20.teamS.serviceRequests.SelectServiceController; -import edu.wpi.cs3733.c20.teamS.serviceRequests.SelectServiceScreen; import edu.wpi.cs3733.c20.teamS.twoFactor.TwoFactorScreen; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Modality; import javafx.stage.Stage; +import javafx.stage.StageStyle; import java.io.IOException; +import java.util.Set; -public class LoginScreen { +public class LoginScreen{ private final Stage stage; private final Stage toPass; private final Scene scene; @@ -32,11 +31,8 @@ private LoginScreen(Stage mainStage) { cont.dialogCompleted().subscribe( next -> { if(next.result()== DialogResult.OK){ - //Intercepthere - //Scene twoFactorScene = new Scene(); - //stage.show + //Intercept here TwoFactorScreen mes = new TwoFactorScreen(toPass, next.value()); - } this.stage.close(); }); @@ -50,10 +46,14 @@ private LoginScreen(Stage mainStage) { catch (IOException ex) { throw new RuntimeException(ex); } + } private void show() { stage.setScene(scene); + Settings.openWindows.add(this.stage); + stage.initStyle(StageStyle.UNDECORATED); + BaseScreen.puggy.register(scene, Event.ANY); stage.show(); } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Main.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Main.java index 3085c0b6..fb396bb8 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Main.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Main.java @@ -1,35 +1,52 @@ package edu.wpi.cs3733.c20.teamS; import edu.wpi.cs3733.c20.teamS.Editing.MapEditingScreen; - +import edu.wpi.cs3733.c20.teamS.applicationInitializer.ApplicationInitializer; import edu.wpi.cs3733.c20.teamS.database.DatabaseController; -import edu.wpi.cs3733.c20.teamS.pathfinding.AStar; +import edu.wpi.cs3733.c20.teamS.emergency.EmergencyScreen; import edu.wpi.cs3733.c20.teamS.serviceRequests.AccessLevel; import edu.wpi.cs3733.c20.teamS.serviceRequests.Employee; import javafx.application.Application; import javafx.stage.Stage; +import javafx.stage.StageStyle; public class Main extends Application { - private static final boolean START_ON_ADMIN_SCREEN = false; - private static final boolean START_ON_SPLASH_SCREEN = true; + private static final StartupScreen START_SCREEN = StartupScreen.SPLASH; public void start(Stage primaryStage) { DatabaseController dbc = new DatabaseController(); dbc.importStartUpData(); + Settings.get().setLoggedIn(new Employee(0, "Default", AccessLevel.USER)); + Settings.get().setPrimaryStage(primaryStage); + new ApplicationInitializer(dbc).initBigFXMLs(); + Settings.get().getPrimaryStage().setFullScreen(false); + Settings.get().getPrimaryStage().setMaximized(true); + Settings.get().getPrimaryStage().initStyle(StageStyle.UNDECORATED); -// if (START_ON_ADMIN_SCREEN) -// new MapEditingScreen(primaryStage, new Employee(17, "Bob", AccessLevel.ADMIN)); -// else -// new MainToLoginScreen(primaryStage, new AStar()); - - if (START_ON_SPLASH_SCREEN) - new MainStartScreen(primaryStage); - else - new MainStartScreen(primaryStage); + switch (START_SCREEN) { + case MAIN: + new MainToLoginScreen(); + break; + case SPLASH: + //new MainStartScreen(primaryStage); + MainStartScreen.showDialog(); + break; + case MAP_EDITING: + Settings.get().setLoggedIn(new Employee(0, "Bob", AccessLevel.ADMIN)); + new MapEditingScreen(); + break; + case EMERGENCY: + new EmergencyScreen(); + break; + default: + throw new IllegalArgumentException("Unexpected value in StartupScreen switch statement."); + } } + //9003,staff,staff,2,Wilson,Wong public static void main(String[] args) { App.launch(); } } + diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/MainStartScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/MainStartScreen.java index d7e119d7..6157c978 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/MainStartScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/MainStartScreen.java @@ -1,48 +1,44 @@ package edu.wpi.cs3733.c20.teamS; -import edu.wpi.cs3733.c20.teamS.pathDisplaying.MainScreenController; -import edu.wpi.cs3733.c20.teamS.pathfinding.IPathfinder; -import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; -import java.io.IOException; - -public class MainStartScreen { - +public class MainStartScreen extends BaseScreen { private MainStartScreenController ui; private Stage stage; private Scene scene; - public MainStartScreen(Stage stage) { + public MainStartScreen() { + this.stage = Settings.get().getPrimaryStage(); + this.scene = this.stage.getScene(); + - this.stage = stage; - FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/SplashScreen.fxml")); - loader.setControllerFactory(c-> { - this.ui = new MainStartScreenController(); - return this.ui; - }); - try { - Parent root = loader.load(); - this.scene = new Scene(root); + if (this.scene == null){ + this.scene = new Scene(Settings.get().getSplashRoot()); } - catch (IOException ex) { - throw new RuntimeException(ex); + else { + this.scene.setRoot(Settings.get().getSplashRoot()); } - //ui.updateFloorDisplay(); + this.show(); - stage.setFullScreen(true); } - public void show() { + + private void show() { stage.setScene(scene); - stage.setMaximized(true); stage.show(); } - - + public static void showDialog() { + MainStartScreen screen = new MainStartScreen(); + for(Stage s : Settings.openWindows){ + s.close(); + //Settings.openWindows.remove(s); + } + Settings.openWindows.clear(); + puggy.pause(); + //screen.show(); + } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/MainStartScreenController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/MainStartScreenController.java index 1b2a2954..d09bc2be 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/MainStartScreenController.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/MainStartScreenController.java @@ -1,7 +1,12 @@ package edu.wpi.cs3733.c20.teamS; +import com.sun.javafx.css.StyleManager; import edu.wpi.cs3733.c20.teamS.pathDisplaying.MainScreenController; import edu.wpi.cs3733.c20.teamS.pathfinding.AStar; +import javafx.animation.Animation; +import javafx.animation.FadeTransition; +import javafx.animation.KeyFrame; +import javafx.animation.Timeline; import javafx.application.Application; import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXTextArea; @@ -15,7 +20,9 @@ import javafx.fxml.Initializable; import javafx.scene.Parent; import javafx.scene.Scene; +import javafx.scene.control.Label; import javafx.scene.control.TextField; +import javafx.scene.effect.BlendMode; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; @@ -27,6 +34,9 @@ import javafx.scene.media.MediaView; import javafx.stage.Modality; import javafx.stage.Stage; +import javafx.util.Duration; +import animatefx.animation.*; + import java.awt.event.ActionListener; @@ -36,12 +46,11 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; +import java.sql.Time; import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.ResourceBundle; +import java.util.*; import java.time.format.DateTimeFormatter; import java.time.LocalDateTime; -import java.util.Timer; public class MainStartScreenController implements Initializable { private MainStartScreen splash; @@ -57,10 +66,8 @@ public class MainStartScreenController implements Initializable { @FXML JFXButton screenButton; @FXML - JFXTextField weatherField; - @FXML - JFXTextArea weatherSummary; - @FXML + Label weatherField; +@FXML JFXTextArea firstTweet; @FXML JFXTextArea secondTweet; @@ -71,47 +78,52 @@ public class MainStartScreenController implements Initializable { @FXML JFXTextArea fifthTweet; @FXML - JFXTextArea timeField; + Label timeField; @FXML ImageView imageID; @FXML StackPane startScreenTap; + ImageView tutorialView; + + LinkedList imageList = new LinkedList<>(); @Override public void initialize(URL location, ResourceBundle resources) { + //timeField.setText(" " + dtf.format(now)); + timeField.setStyle("-fx-font-size: 60px"); + initClock(); - timeBox.setStyle("-fx-background-color: rgba(255, 255, 255, 255);"); - - DateTimeFormatter dtf = DateTimeFormatter.ofPattern(" HH:mm:ss"); - LocalDateTime now = LocalDateTime.now(); - + WeatherBox weatherBox1 = new WeatherBox(); - timeField.setText(" " + dtf.format(now)); - timeField.setStyle("-fx-font-size: 40px"); + weatherField.setText((String.valueOf(weatherBox1.getTemp())) + "\u00B0"); + weatherField.setStyle("-fx-font-size: 50px"); - WeatherBox weatherBox1 = new WeatherBox(); + //HashSet imageList = new HashSet<>(); + Image image0 = new Image(String.valueOf(getClass().getResource("/images/TutorialPhotos/image1.png"))); + imageList.add(image0); + Image image1 = new Image(String.valueOf(getClass().getResource("/images/TutorialPhotos/image1.png"))); + imageList.add(image1); + Image image2 = new Image(String.valueOf(getClass().getResource("/images/TutorialPhotos/image2.png"))); + imageList.add(image2); + Image image3 = new Image(String.valueOf(getClass().getResource("/images/TutorialPhotos/image3.png"))); + imageList.add(image3); - weatherField.setText((String.valueOf(" " + weatherBox1.getTemp())) + " Degrees"); - weatherField.setStyle("-fx-font-size: 16px"); - weatherSummary.setText(" " + weatherBox1.summary()); - weatherSummary.setStyle("-fx-font-size: 25px"); - //weatherSummary.setStyle("-fx-padding: 0 10 0 10"); String icon = weatherBox1.icon(); if (icon.contains("clear") && icon.contains("day")) { - icon = "weatherIcons/SunImage.jpeg"; + icon = "weatherIcons/SunImage.png"; } else if (icon.contains("clear") && icon.contains("night")) { - icon = "weatherIcons/MoonImage.jpeg"; + icon = "weatherIcons/MoonImage.png"; } else if (icon.contains("rain") || icon.contains("sleet")) { icon = "weatherIcons/rain.png"; } else if (icon.contains("partly") && icon.contains("day")) { icon = "weatherIcons/PartlyCloudy.png"; } else if (icon.contains("partly") && icon.contains("night")) { - icon = "weatherIcons/PartlyCloudyNightImage.png"; + icon = "weatherIcons/PartlyCloudyNight.png"; } else if (icon.contains("cloudy")) { icon = "weatherIcons/Cloudy.png"; } else if (icon.contains("fog")) { @@ -124,44 +136,116 @@ public void initialize(URL location, ResourceBundle resources) { icon = "weatherIcons/ThunderStorm.png"; } - Image image = new Image(String.valueOf(getClass().getResource("/images/" + icon))); imageID.setImage(image); imageID.setFitHeight(171); - imageID.setFitWidth(289); + imageID.setFitWidth(171); imageID.setPreserveRatio(false); - Tweetbox tweetbox = new Tweetbox(); - - firstTweet.setText(tweetbox.getTweets("@FaulknerHosp").get(1)); - firstTweet.setStyle("-fx-text-fill: white"); - secondTweet.setText(tweetbox.getTweets("@FaulknerHosp").get(2)); - secondTweet.setStyle("-fx-text-fill: white"); - ThirdTweet.setText(tweetbox.getTweets("@FaulknerHosp").get(3)); - ThirdTweet.setStyle("-fx-text-fill: white"); - fourthTweet.setText(tweetbox.getTweets("@FaulknerHosp").get(4)); - fourthTweet.setStyle("-fx-text-fill: white"); - fifthTweet.setText(tweetbox.getTweets("@FaulknerHosp").get(5)); - fifthTweet.setStyle("-fx-text-fill: white"); - - ImageView tutorialView = new ImageView(); + + try{ + Tweetbox tweetbox = new Tweetbox(); + + firstTweet.setText(tweetbox.getTweets("@FaulknerHosp").get(0)); + firstTweet.setStyle("-fx-text-fill: white"); + secondTweet.setText(tweetbox.getTweets("@FaulknerHosp").get(1)); + secondTweet.setStyle("-fx-text-fill: white"); + ThirdTweet.setText(tweetbox.getTweets("@FaulknerHosp").get(2)); + ThirdTweet.setStyle("-fx-text-fill: white"); + fourthTweet.setText(tweetbox.getTweets("@FaulknerHosp").get(3)); + fourthTweet.setStyle("-fx-text-fill: white"); + fifthTweet.setText(tweetbox.getTweets("@FaulknerHosp").get(4)); + fifthTweet.setStyle("-fx-text-fill: white"); + } + catch (Exception e){ + System.out.println("Twitter timed out."); + } + + + tutorialView = new ImageView(); startScreenTap.getChildren().add(tutorialView); - tutorialView.setImage(new Image(this.getClass().getResource("/images/PugLickingScreen.gif").toExternalForm())); +// tutorialView.setImage(new Image(this.getClass().getResource("/images/PugLickingScreen.gif").toExternalForm())); tutorialView.setPreserveRatio(true); + //tutorialView.s tutorialView.fitWidthProperty().bind(startScreenTap.widthProperty()); + //tutorialView.applyCss("-fx-bordercolor"); + ImageSelector is = new ImageSelector(); + imageChangeTimer(is); } - MainStartScreenController() { + public MainStartScreenController() { } @FXML private void onScreenClicked(ActionEvent event) { - MainToLoginScreen maintolog = new MainToLoginScreen((Stage) (startScreenTap.getScene().getWindow())); - maintolog.show(); + //MainToLoginScreen maintolog = new MainToLoginScreen((Stage) (startScreenTap.getScene().getWindow())); + Application.setUserAgentStylesheet("modena.css"); + StyleManager.getInstance().addUserAgentStylesheet("default.css"); + MainToLoginScreen.showDialog(); + } + + + private void initClock() { + Timeline clock = new Timeline(new KeyFrame(Duration.ZERO, e -> { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("h:mm a"); + timeField.setText(LocalDateTime.now().format(formatter)); + }), new KeyFrame(Duration.seconds(1))); + clock.setCycleCount(Animation.INDEFINITE); + clock.play(); } + + private void imageChangeTimer(ImageSelector is){ + Timeline imageTimer = new Timeline(new KeyFrame(Duration.seconds(4),e->{ + setTutorial(is.getImage()); + })); + imageTimer.setCycleCount(Animation.INDEFINITE); + imageTimer.play(); + } + + void setTutorial(int image){ + ///Image tutImage = new Image(String.valueOf(getClass().getResource("/images/TutorialPhotos/image" + image + ".png"))); + //new FadeIn(tutorialView).setResetOnFinished(true).play(); + new FadeOut(tutorialView).play(); + tutorialView.setOpacity(0); + tutorialView.setImage(imageList.get(image)); + //tutorialView.setPreserveRatio(true); + //tutorialView.fitWidthProperty().bind(startScreenTap.widthProperty()); + tutorialView.setOpacity(0); + new FadeIn(tutorialView).play(); + //tutorialView.setOpacity(1); + + } + + static class ImageSelector{ + private static int image; + ImageSelector(){ + image = 1; + } + private static void nextImage(){ + if(image == 3){ + image = 1; + }else{ + image++; + } + } + + static int getImage(){ + int val = image; + nextImage(); + //System.out.println("Image is "+ val); + return val; + } + } + + + private void fireAlarm(){ + + } + } + diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/MainToLoginScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/MainToLoginScreen.java index 6d6cf96e..88ad09af 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/MainToLoginScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/MainToLoginScreen.java @@ -1,42 +1,45 @@ package edu.wpi.cs3733.c20.teamS; +import animatefx.animation.FadeOut; import edu.wpi.cs3733.c20.teamS.pathDisplaying.MainScreenController; -import edu.wpi.cs3733.c20.teamS.pathfinding.IPathfinder; -import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; +import javafx.event.Event; import javafx.scene.Scene; import javafx.stage.Stage; -import java.io.IOException; /** * Simple screen for main client ui */ -public class MainToLoginScreen { - private MainScreenController ui; +public class MainToLoginScreen extends BaseScreen { + private Scene scene; private Stage stage; - public MainToLoginScreen(Stage stage) { - this.stage = stage; - FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/UI_client.fxml")); - loader.setControllerFactory(c -> { - this.ui = new MainScreenController(stage); - return this.ui; - }); - try { - Parent root = loader.load(); - this.scene = new Scene(root); + public MainToLoginScreen() { + this.stage = Settings.get().getPrimaryStage(); + this.scene = stage.getScene(); + Settings.get().getMainScreenController().setDirectVisible(); + + Settings set = Settings.get(); + if (this.scene == null){ + this.scene = new Scene(Settings.get().getMainScreenRoot()); } - catch (IOException ex) { - throw new RuntimeException(ex); + else { + this.scene.setRoot(Settings.get().getMainScreenRoot()); } - //ui.updateFloorDisplay(); + this.show(); - stage.setFullScreen(true); + } - public void show() { + private void show() { stage.setScene(scene); - stage.setMaximized(true); + puggy.register(scene, Event.ANY); stage.show(); + Settings.get().getMainScreenController().clearPathDisplay(); } + public static void showDialog() { + puggy.play(); + MainToLoginScreen screen = new MainToLoginScreen(); + } + + } \ No newline at end of file diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/SendTextDirectionsScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/SendTextDirectionsScreen.java index 3e9248ca..37c850ea 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/SendTextDirectionsScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/SendTextDirectionsScreen.java @@ -1,17 +1,17 @@ package edu.wpi.cs3733.c20.teamS; -import edu.wpi.cs3733.c20.teamS.serviceRequests.Employee; import edu.wpi.cs3733.c20.teamS.utilities.SendEmailDirectionsThread; import edu.wpi.cs3733.c20.teamS.utilities.SendTextDirectionsThread; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Modality; import javafx.stage.Stage; +import javafx.stage.StageStyle; import java.io.IOException; import java.util.List; -import java.util.Set; public class SendTextDirectionsScreen { @@ -43,6 +43,9 @@ private SendTextDirectionsScreen(List directions) { private void show() { stage.setScene(scene); + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); + stage.initStyle(StageStyle.UNDECORATED); stage.show(); } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/SerialPoller.java b/src/main/java/edu/wpi/cs3733/c20/teamS/SerialPoller.java new file mode 100644 index 00000000..4c1055e0 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/SerialPoller.java @@ -0,0 +1,158 @@ +package edu.wpi.cs3733.c20.teamS; + +import com.fazecast.jSerialComm.SerialPort; +import com.fazecast.jSerialComm.SerialPortDataListener; +import com.fazecast.jSerialComm.SerialPortEvent; +import gnu.io.NRSerialPort; +import javafx.application.Application; +import javafx.stage.Stage; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +import static java.lang.Thread.sleep; + + +public class SerialPoller extends Application{ + + public static void sensor() throws Exception{ +// SerialPort sp = SerialPort.getCommPort("/dev/cu.usbserial-DN03ADR9"); +// sp.setComPortParameters(9600, 8, 1, 0); +// sp.setComPortTimeouts(SerialPort.TIMEOUT_WRITE_BLOCKING, 0, 0); +// for(String s:NRSerialPort.getAvailableSerialPorts()){ +// System.out.println("Availible port: "+s); +// } + String port = "/dev/tty.usbserial-DN03ADR9"; + int baudRate = 9600; + NRSerialPort serial = new NRSerialPort(port, baudRate); + //Thread.sleep(800); + serial.connect(); + Thread.sleep(800); + DataInputStream ins = new DataInputStream(serial.getInputStream()); + //Thread.sleep(800); +// DataOutputStream outs = new DataOutputStream(serial.getOutputStream()); + Thread.sleep(800); + short b = 0; + char c = 'o'; + //byte[] buffer = new byte[2]; + byte[] fireBall = new byte[2]; + //System.out.println("Bytes avalible: " + ins.available()); + int i = 0; + //ByteBuffer bb = ByteBuffer + //byte[] biteArray = new byte[2]; + while(i<100){ + //System.out.println(ins.available()); + Thread.sleep (200); + ins.read(fireBall); + //System.out.println(ByteBuffer.wrap(fireBall).getChar()); + System.out.println((char) fireBall[1]); + + i++; + } + //outs.write(b); + String print = "Value = "+b; + System.out.println(print); + + if( b > 51){ + System.out.println("IT'S BRIGHT MY FRIEND"); + + + + } + else{ + System.out.println("IT'S DARK MY FRIEND"); + } + + + + + + } + + + + + public void start(Stage primaryStage) throws Exception { + //sensor(); + runSensor(); + } + + private static String port; + private static int baudRate; + public static NRSerialPort serial; + + public static void initSensor(){ + port = "/dev/tty.usbserial-DN03ADR9"; + baudRate = 9600; + serial = new NRSerialPort(port,baudRate); + serial.connect(); + } + + public static boolean runSensor(){ +// String port = "/dev/tty.usbserial-DN03ADR9"; +// int baudRate = 9600; +// NRSerialPort serial = new NRSerialPort(port, baudRate); + + try { + + + //Thread.sleep(800); + //serial.connect(); + //Thread.sleep(800); + DataInputStream ins = new DataInputStream(serial.getInputStream()); + //serial.getInputStream(). + //Thread.sleep(800); +// DataOutputStream outs = new DataOutputStream(serial.getOutputStream()); + //Thread.sleep(800); +// while(ins.available() !=0){ +// Thread.sleep (10); +// } + byte[] fireBall = new byte[2]; + + //int b = ins.read(); +// while(true){ +// Thread.sleep (200); +// +// //System.out.println(ByteBuffer.wrap(fireBall).getChar()); +// +// System.out.println((char) fireBall[1]); + +// } +// while(true){ +// +// +// +// //System.out.println((char) fireBall[0]); +// if (((char) fireBall[0] == 'f') || (char) fireBall[0] == 's') { +// break; +// } +// } + + ins.read(fireBall); + + System.out.println((char) fireBall[0]); + if ((char) fireBall[0] == 'f') { + //serial.disconnect(); + return true; + } + else { + //serial.disconnect(); + return false; + } + //fw.start(new Stage()); + // + + + } catch (Exception e) { + e.printStackTrace(); + } + //serial.disconnect(); + return false; + } + + + + +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/Settings.java b/src/main/java/edu/wpi/cs3733/c20/teamS/Settings.java index 73dbb6cb..f50a70c3 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/Settings.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/Settings.java @@ -1,9 +1,17 @@ package edu.wpi.cs3733.c20.teamS; +import edu.wpi.cs3733.c20.teamS.Editing.EditScreenController; +import edu.wpi.cs3733.c20.teamS.pathDisplaying.MainScreenController; import edu.wpi.cs3733.c20.teamS.pathfinding.AStar; - import edu.wpi.cs3733.c20.teamS.pathfinding.PathfindingContext; +import edu.wpi.cs3733.c20.teamS.serviceRequests.Employee; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; import javafx.scene.paint.Color; +import javafx.stage.Stage; + +import java.util.HashSet; +import java.util.Set; public final class Settings { private final PathfindingContext pathfinder = new PathfindingContext(new AStar()); @@ -19,19 +27,29 @@ public Color nodeColorElevator() { return Color.GREEN.deriveColor(1, 1, 1, 0.5); } public Color nodeFillColorNormal() { - return Color.ORANGE.deriveColor(1, 1, 1, 0.5); + //return Color.RED.deriveColor(1, 1, 1, 0.5); + return Color.web("#056F75").deriveColor(1, 1, 1, 0.5); } public Color nodeStrokeColorNormal() { - return Color.ORANGE; + //return Color.RED; + return Color.web("#2FBAC2"); } public Color nodeFillColorHighlight() { return Color.AQUA.deriveColor(1, 1, 1, 0.5); } - public Color editHitboxColor() { - return Color.BLUE.deriveColor(1, 1, 1, .45); + public Color editRoomColorNormal() { + //return Color.BLUE.deriveColor(1, 1, 1, .45); + return Color.web("#C2692F", .45); + } + public Color editRoomColorHighlight() { + return Color.AQUA.deriveColor(1, 1, 1, 0.5); + } + public int editRoomVertexRadius() { + return 5; } public Color editEdgeColorNormal() { - return Color.BLUE; + return Color.web("#2FBAC2"); + //return Color.BLUE; } public Color editEdgeColorHighlight() { return Color.AQUA; @@ -39,6 +57,22 @@ public Color editEdgeColorHighlight() { public int editEdgeStrokeWidth() { return 5; } + public double editEdgeEnlargeRatio() { + return 2.5; + } + public double editEdgeCollisionMaskWidth() { + return 15; + } + public int minZoomStage() { + return -2; + } + public int maxZoomStage() { + return 0; + } + + public int floors() { + return 7; + } /** * Whether to should use the node-placing tool that doesn't require a dialog interaction. @@ -57,14 +91,97 @@ public void setUseQuickNodePlacingTool(boolean value) { private Settings(){} - private static class SingletonHelper { + private static Settings set; + + synchronized public static Settings get(){ + + if (set == null) + { + // if instance is null, initialize + set = new Settings(); + } + return set; + } + + + public static Set openWindows = new HashSet<>(); + + static FXMLLoader singleLoader; + + public Set getOpenWindows() { + return openWindows; + } + + public void setOpenWindows(Set openWindows) { + Settings.openWindows = openWindows; + } + + public Stage getPrimaryStage() { + return primaryStage; + } + + public void setPrimaryStage(Stage primaryStage) { + Settings.primaryStage = primaryStage; + } + + public Parent getMainScreenRoot() { + return mainScreenRoot; + } + + public void setMainScreenRoot(Parent mainScreenRoot) { + Settings.mainScreenRoot = mainScreenRoot; + } + + public Parent getSplashRoot() { + return splashRoot; + } + + public void setSplashRoot(Parent splashRoot) { + Settings.splashRoot = splashRoot; + } + + public Parent getEmployeeRoot() { + return employeeRoot; + } + + public void setEmployeeRoot(Parent employeeRoot) { + Settings.employeeRoot = employeeRoot; + } + + public Employee getLoggedIn() { + return loggedIn; + } + + public void setLoggedIn(Employee loggedIn) { + Settings.loggedIn = loggedIn; + } + + public MainScreenController getMainScreenController() { + return mainScreenController; + } + + public void setMainScreenController(MainScreenController mainScreenController) { + Settings.mainScreenController = mainScreenController; + } + + public EditScreenController getEditScreenController() { + return editScreenController; + } - private static final Settings settings = new Settings(); + public void setEditScreenController(EditScreenController editScreenController) { + Settings.editScreenController = editScreenController; } - public static Settings get(){ - return SingletonHelper.settings; + public boolean showPopupsOnRoomMouseOver() { + return false; } + private static Stage primaryStage; + private static Parent mainScreenRoot; + private static Parent splashRoot; + private static Parent employeeRoot; + private static edu.wpi.cs3733.c20.teamS.serviceRequests.Employee loggedIn = null; + private static MainScreenController mainScreenController; + private static EditScreenController editScreenController; } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/StartupScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/StartupScreen.java new file mode 100644 index 00000000..8a365e9c --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/StartupScreen.java @@ -0,0 +1,8 @@ +package edu.wpi.cs3733.c20.teamS; + +public enum StartupScreen { + MAIN, + SPLASH, + MAP_EDITING, + EMERGENCY +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/ActiveServiceRequestScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/ActiveServiceRequestScreen.java index eb0bc4c2..8ab2bdba 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/ActiveServiceRequestScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/ActiveServiceRequestScreen.java @@ -1,7 +1,10 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.database.ServiceData; import javafx.collections.ObservableList; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -16,9 +19,9 @@ * Also, it should update the status of selected ServiceRequest upon clicking "Completed" */ public class ActiveServiceRequestScreen { - private ActiveServiceRequestScreenController screenController; + //private ActiveServiceRequestScreenController screenController; //private DatabaseController databaseController; - private ObservableList activeRequests; + //private ObservableList activeRequests; private Stage stage; private Scene scene; @@ -34,19 +37,45 @@ public Set activeRequests(){ } */ - public ActiveServiceRequestScreen(ObservableList requests){ +// public ActiveServiceRequestScreen(ObservableList requests){ +// +// //if(employee == null) ThrowHelper.illegalNull("employee"); +// this.stage = new Stage(); +// stage.initModality(Modality.APPLICATION_MODAL); +// stage.setResizable(false); +// //this.loggedIn = employee; +// this.activeRequests = requests; +// FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/ActiveServiceRequestScreen.fxml")); +// loader.setControllerFactory(c -> { +//// this.screenController = new ActiveServiceRequestScreenController(this.stage, this.activeRequests); +//// return this.screenController; +// ActiveServiceRequestScreenController cont = new ActiveServiceRequestScreenController(activeRequests); +// return cont; +// }); +// +// try{ +// Parent root = loader.load(); +// this.scene = new Scene(root); +// }catch(IOException ex){ +// throw new RuntimeException(ex); +// } +// } + + + public ActiveServiceRequestScreen(){ //if(employee == null) ThrowHelper.illegalNull("employee"); this.stage = new Stage(); stage.initModality(Modality.APPLICATION_MODAL); stage.setResizable(false); //this.loggedIn = employee; - this.activeRequests = requests; + //this.activeRequests = requests; FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/ActiveServiceRequestScreen.fxml")); loader.setControllerFactory(c -> { // this.screenController = new ActiveServiceRequestScreenController(this.stage, this.activeRequests); // return this.screenController; - ActiveServiceRequestScreenController cont = new ActiveServiceRequestScreenController(activeRequests); + //ActiveServiceRequestScreenController cont = new ActiveServiceRequestScreenController(activeRequests); + ActiveServiceRequestScreenController cont = new ActiveServiceRequestScreenController(); return cont; }); @@ -56,17 +85,19 @@ public ActiveServiceRequestScreen(ObservableList requests){ }catch(IOException ex){ throw new RuntimeException(ex); } + //puggy.register(scene, Event.ANY); } private void show() { stage.setScene(scene); - + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); stage.show(); } - public static void showDialog(ObservableList requests) { - ActiveServiceRequestScreen screen = new ActiveServiceRequestScreen(requests); + public static void showDialog() { + ActiveServiceRequestScreen screen = new ActiveServiceRequestScreen(); //screen.screenController.showActiveRequests(); screen.show(); } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/ActiveServiceRequestScreenController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/ActiveServiceRequestScreenController.java index 3e5ca507..3b8c804d 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/ActiveServiceRequestScreenController.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/ActiveServiceRequestScreenController.java @@ -4,13 +4,21 @@ import edu.wpi.cs3733.c20.teamS.database.DatabaseController; import edu.wpi.cs3733.c20.teamS.database.ServiceData; import javafx.beans.property.ReadOnlyObjectWrapper; +import javafx.beans.value.ObservableValue; +import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; +import javafx.fxml.Initializable; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.stage.Stage; +import javafx.util.Callback; -public class ActiveServiceRequestScreenController { +import java.net.URL; +import java.util.ResourceBundle; +import java.util.Set; + +public class ActiveServiceRequestScreenController implements Initializable { @FXML private TableView serviceRequestTable; @FXML private JFXButton cancelButton; @FXML private TableColumn serviceIDCol; @@ -19,23 +27,32 @@ public class ActiveServiceRequestScreenController { @FXML private TableColumn messageCol; @FXML private TableColumn locationCol; @FXML private TableColumn typeCol; + @FXML private JFXButton assignButton; + @FXML private JFXButton completeButton; private ObservableList activeRequests; @FXML - public void initialize() { + public void initialize(URL location, ResourceBundle resources) { + this.activeRequests = FXCollections.observableArrayList(); + this.update(); showActiveRequests(); } - public ActiveServiceRequestScreenController(ObservableList requests){ - this.serviceRequestTable = new TableView<>(); - this.activeRequests = requests; + +// public ActiveServiceRequestScreenController(ObservableList requests){ +// this.serviceRequestTable = new TableView<>(); +// this.activeRequests = requests; +// } + + public ActiveServiceRequestScreenController(){ + } /** * show active ServiceRequests in the TableView */ - public void showActiveRequests(){ + public void showActiveRequests() { serviceRequestTable.setItems(this.activeRequests); serviceIDCol = new TableColumn<>("Service ID"); assignedEmployeeCol = new TableColumn<>("Employee Assigned"); @@ -45,12 +62,21 @@ public void showActiveRequests(){ typeCol = new TableColumn<>("Type"); serviceIDCol.setCellValueFactory(p -> new ReadOnlyObjectWrapper(p.getValue().getServiceID())); - assignedEmployeeCol.setCellValueFactory(p -> new ReadOnlyObjectWrapper(p.getValue().getAssignedEmployeeID())); + //assignedEmployeeCol.setCellValueFactory(p -> new ReadOnlyObjectWrapper(p.getValue().getAssignedEmployeeID())); + assignedEmployeeCol.setCellValueFactory(new Callback, ObservableValue>() { + public ObservableValue call(TableColumn.CellDataFeatures p) { + if(p.getValue().getAssignedEmployeeID() == 0){ + return null; + } + return new ReadOnlyObjectWrapper(p.getValue().getAssignedEmployeeID()); + } + }); statusCol.setCellValueFactory(p -> new ReadOnlyObjectWrapper(p.getValue().getStatus())); messageCol.setCellValueFactory(p -> new ReadOnlyObjectWrapper(p.getValue().getMessage())); locationCol.setCellValueFactory(p -> new ReadOnlyObjectWrapper(p.getValue().getServiceNode())); typeCol.setCellValueFactory(p -> new ReadOnlyObjectWrapper(p.getValue().getServiceType())); + this.serviceRequestTable.setItems(this.activeRequests); serviceRequestTable.getColumns().setAll( serviceIDCol, assignedEmployeeCol, statusCol, messageCol, locationCol, typeCol); @@ -60,15 +86,44 @@ public void showActiveRequests(){ * Remove all selected ServiceRequest upon clicking the Complete button */ @FXML void onCompleteClicked(){ - ObservableList selected = this.serviceRequestTable.getSelectionModel().getSelectedItems(); +// ObservableList selected = this.serviceRequestTable.getSelectionModel().getSelectedItems(); +// DatabaseController dbc = new DatabaseController(); +// for(ServiceData service : selected){ +// dbc.deleteServiceWithId(service.getServiceID()); +// dbc.commit(); +// this.activeRequests.remove(service); +// } + + ServiceData selected = this.serviceRequestTable.getSelectionModel().getSelectedItem(); DatabaseController dbc = new DatabaseController(); - for(ServiceData service : selected){ - dbc.deleteServiceWithId(service.getServiceID()); - dbc.commit(); - this.activeRequests.remove(service); - } + dbc.deleteServiceWithId(selected.getServiceID()); + dbc.commit(); + this.update(); } + /** + * Open dialog for AssignEmployeeScreen + */ + @FXML void onAssignClicked(){ + ServiceData selected = this.serviceRequestTable.getSelectionModel().getSelectedItem(); + AssignEmployeeScreen.showDialog(selected, this); + } + + + /** + * Load existing ServiceData from database and update the screen + */ + public void update(){ + DatabaseController dbController = new DatabaseController(); + Set dbServices = dbController.getAllServiceRequestData(); + //ObservableList activeServices = FXCollections.observableArrayList(); + //activeServices.addAll(dbServices); + this.activeRequests.removeAll(this.activeRequests); + this.activeRequests.addAll(dbServices); + //this.activeRequests = activeServices; + } + + @FXML void onCancelClicked(){ Stage toClose = (Stage)cancelButton.getScene().getWindow(); toClose.close(); diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/AssignEmployeeScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/AssignEmployeeScreen.java new file mode 100644 index 00000000..edd8fe6e --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/AssignEmployeeScreen.java @@ -0,0 +1,48 @@ +package edu.wpi.cs3733.c20.teamS.app.serviceRequests; + +import edu.wpi.cs3733.c20.teamS.database.ServiceData; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Modality; +import javafx.stage.Stage; + +import java.io.IOException; + +public class AssignEmployeeScreen { + //private AssignEmployeeScreenController controller; + private Stage stage; + private Scene scene; + private ServiceData tbAssigned; + private ActiveServiceRequestScreenController controller; + + public AssignEmployeeScreen(ServiceData selected, ActiveServiceRequestScreenController controller){ + this.stage = new Stage(); + this.tbAssigned = selected; + this.controller = controller; + stage.initModality(Modality.APPLICATION_MODAL); + stage.setResizable(false); + FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/AssignEmployeeScreen.fxml")); + loader.setControllerFactory(c -> { + AssignEmployeeScreenController cont = new AssignEmployeeScreenController(this.tbAssigned, this. controller); + return cont; + }); + + try{ + Parent root = loader.load(); + this.scene = new Scene(root); + }catch(IOException ex){ + throw new RuntimeException(ex); + } + } + + private void show(){ + stage.setScene(scene); + stage.show(); + } + + public static void showDialog(ServiceData selected, ActiveServiceRequestScreenController controller){ + AssignEmployeeScreen screen = new AssignEmployeeScreen(selected, controller); + screen.show(); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/AssignEmployeeScreenController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/AssignEmployeeScreenController.java new file mode 100644 index 00000000..96f38b04 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/AssignEmployeeScreenController.java @@ -0,0 +1,91 @@ +package edu.wpi.cs3733.c20.teamS.app.serviceRequests; + +import com.jfoenix.controls.JFXButton; +import edu.wpi.cs3733.c20.teamS.database.DatabaseController; +import edu.wpi.cs3733.c20.teamS.database.EmployeeData; +import edu.wpi.cs3733.c20.teamS.database.ServiceData; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TextField; + +import javafx.scene.control.TableView; +import javafx.scene.control.cell.PropertyValueFactory; + +import java.net.URL; +import java.util.HashSet; +import java.util.ResourceBundle; +import java.util.Set; + +public class AssignEmployeeScreenController implements Initializable{ + @FXML private TextField assigneeID; + @FXML private TextField assigneeFirstName; + @FXML private TextField assigneeLastName; + @FXML private JFXButton assignButton; + @FXML private TableView capEmployeeTable; + @FXML private TableColumn capEmployeeIDCol; + @FXML private TableColumn capEmployeeFirstNameCol; + @FXML private TableColumn capEmployeeLastNameCol; + + private ObservableList capEmployees; + private ServiceData tbAssigned; + private ActiveServiceRequestScreenController cont; + + @FXML + public void initialize(URL location, ResourceBundle resources){ + this.capEmployees = FXCollections.observableArrayList(); + this.update(); + + capEmployeeIDCol.setCellValueFactory(new PropertyValueFactory("EmployeeID")); + capEmployeeFirstNameCol.setCellValueFactory(new PropertyValueFactory("FirstName")); + capEmployeeLastNameCol.setCellValueFactory(new PropertyValueFactory("LastName")); + + capEmployeeTable.setItems(capEmployees); + } + + public AssignEmployeeScreenController(ServiceData tbAssigned, ActiveServiceRequestScreenController controller){ + this.tbAssigned = tbAssigned; + this.cont = controller; + } + + @FXML void onAssignClicked(){ + EmployeeData selected = this.capEmployeeTable.getSelectionModel().getSelectedItem(); + this.tbAssigned.setStatus("ASSIGNED"); + this.tbAssigned.setAssignedEmployeeID(selected.getEmployeeID()); + DatabaseController dbc = new DatabaseController(); + dbc.updateServiceData(this.tbAssigned); + this.update(); + this.cont.update(); + } + + public void update(){ + DatabaseController dbc = new DatabaseController(); + Set allEmployees = dbc.getAllEmployeeData(); + Set capEmployees = new HashSet<>(); + for(EmployeeData em : allEmployees){ + if(dbc.checkCapable(em.getEmployeeID(), this.tbAssigned.getServiceType())){ + capEmployees.add(em); + } + } + this.capEmployees.removeAll(this.capEmployees); + this.capEmployees.addAll(capEmployees); + EmployeeData currAssignee = null; + for(EmployeeData em : this.capEmployees){ + if(em.getEmployeeID() == (this.tbAssigned.getAssignedEmployeeID())){ + currAssignee = em; + break; + } + } + + this.capEmployees.removeAll(currAssignee); + if(currAssignee != null) { + this.assigneeID.setText(Integer.toString(currAssignee.getEmployeeID())); + this.assigneeFirstName.setText(currAssignee.getFirstName()); + this.assigneeLastName.setText(currAssignee.getLastName()); + } + } + + +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/DrugRequestScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/DrugRequestScreen.java index 83f12e54..59a11427 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/DrugRequestScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/DrugRequestScreen.java @@ -1,5 +1,7 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; import edu.wpi.cs3733.c20.teamS.app.DialogResult; @@ -9,6 +11,7 @@ import edu.wpi.cs3733.c20.teamS.serviceRequests.Employee; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -70,6 +73,10 @@ public static Observable> showDialog(Employee em private void show() { stage.setScene(scene); + + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); + stage.show(); } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/FloristRequestController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/FloristRequestController.java index 6c4360f9..8ee0fede 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/FloristRequestController.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/FloristRequestController.java @@ -25,7 +25,7 @@ public class FloristRequestController { private JFXTextField locationField; @FXML - private JFXTextArea commentsField; + private JFXTextField commentsField; diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/FloristRequestScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/FloristRequestScreen.java index 3ac7d176..fc803693 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/FloristRequestScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/FloristRequestScreen.java @@ -1,5 +1,7 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; import edu.wpi.cs3733.c20.teamS.app.DialogResult; @@ -9,6 +11,7 @@ import edu.wpi.cs3733.c20.teamS.serviceRequests.Employee; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -71,6 +74,8 @@ public static Observable> showDialog(Employee private void show() { stage.setScene(scene); + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); stage.show(); } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/GiftRequestScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/GiftRequestScreen.java index 7ceb6fb1..26f7b8fe 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/GiftRequestScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/GiftRequestScreen.java @@ -1,4 +1,6 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; import edu.wpi.cs3733.c20.teamS.app.DialogResult; @@ -11,6 +13,7 @@ import edu.wpi.cs3733.c20.teamS.serviceRequests.GiftServiceRequest; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -64,6 +67,10 @@ public static Observable> showDialog(Employee em private void show() { stage.setScene(scene); + + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); + stage.show(); } } \ No newline at end of file diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/InterpreterRequestScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/InterpreterRequestScreen.java index eaf14593..fb321192 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/InterpreterRequestScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/InterpreterRequestScreen.java @@ -1,5 +1,7 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; import edu.wpi.cs3733.c20.teamS.app.DialogResult; @@ -9,6 +11,7 @@ import edu.wpi.cs3733.c20.teamS.serviceRequests.Employee; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -72,6 +75,10 @@ public static Observable> showDialog(Empl private void show() { stage.setScene(scene); + + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); + stage.show(); } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/JanitorRequestScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/JanitorRequestScreen.java index 616ae8f3..ce5d8dab 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/JanitorRequestScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/JanitorRequestScreen.java @@ -1,5 +1,7 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; import edu.wpi.cs3733.c20.teamS.app.DialogResult; @@ -11,6 +13,7 @@ import edu.wpi.cs3733.c20.teamS.serviceRequests.Employee; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -74,6 +77,8 @@ public static Observable> showDialog(Employee private void show() { stage.setScene(scene); stage.initModality(Modality.APPLICATION_MODAL); + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); stage.show(); } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/LastRitesRequestScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/LastRitesRequestScreen.java index 95164d17..fa4851e4 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/LastRitesRequestScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/LastRitesRequestScreen.java @@ -1,5 +1,7 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; import edu.wpi.cs3733.c20.teamS.app.DialogResult; @@ -9,6 +11,7 @@ import edu.wpi.cs3733.c20.teamS.serviceRequests.LastRitesRequest; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -73,6 +76,8 @@ public static Observable> showDialog(Employee empl private void show() { stage.setScene(scene); stage.initModality(Modality.APPLICATION_MODAL); + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); stage.show(); } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/LaundryRequestScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/LaundryRequestScreen.java index 7af64ccc..38b7937d 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/LaundryRequestScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/LaundryRequestScreen.java @@ -1,5 +1,7 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; import edu.wpi.cs3733.c20.teamS.app.DialogResult; @@ -10,6 +12,7 @@ import edu.wpi.cs3733.c20.teamS.serviceRequests.Employee; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -72,6 +75,8 @@ public static Observable> showDialog(Employee private void show() { stage.setScene(scene); stage.initModality(Modality.APPLICATION_MODAL); + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); stage.show(); } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/MaintenanceServiceRequestScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/MaintenanceServiceRequestScreen.java index 1156f703..dc8794d9 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/MaintenanceServiceRequestScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/MaintenanceServiceRequestScreen.java @@ -1,6 +1,8 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; import edu.wpi.cs3733.c20.teamS.Main; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; import edu.wpi.cs3733.c20.teamS.app.DialogResult; @@ -10,6 +12,7 @@ import edu.wpi.cs3733.c20.teamS.serviceRequests.MaintenanceServiceRequest; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -74,6 +77,8 @@ public static Observable> showDialog(Empl private void show(){ this.stage.setScene(this.scene); + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); this.stage.show(); } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/RideRequestScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/RideRequestScreen.java index f0917e0e..b462861a 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/RideRequestScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/RideRequestScreen.java @@ -1,5 +1,7 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; import edu.wpi.cs3733.c20.teamS.app.DialogResult; @@ -9,6 +11,7 @@ import edu.wpi.cs3733.c20.teamS.serviceRequests.RideServiceRequest; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -63,6 +66,8 @@ private void onDialogCompleted(DialogEvent next) { private void show() { stage.setScene(scene); + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); stage.show(); } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/SecurityServiceScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/SecurityServiceScreen.java index 9797425f..be6da3d9 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/SecurityServiceScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/SecurityServiceScreen.java @@ -1,5 +1,7 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; import edu.wpi.cs3733.c20.teamS.app.DialogResult; @@ -10,6 +12,7 @@ import edu.wpi.cs3733.c20.teamS.serviceRequests.SecurityServiceRequest; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -71,6 +74,8 @@ public static Observable> showDialog(Employe private void show() { stage.setScene(scene); + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); stage.show(); } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/ServiceTechRequestScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/ServiceTechRequestScreen.java index 8f9beae1..eb34ee36 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/ServiceTechRequestScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/ServiceTechRequestScreen.java @@ -1,5 +1,7 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; import edu.wpi.cs3733.c20.teamS.app.DialogResult; @@ -11,6 +13,7 @@ import edu.wpi.cs3733.c20.teamS.serviceRequests.ServiceTechServiceRequest; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -67,6 +70,8 @@ public static Observable> showDialog(Empl private void show() { stage.setScene(scene); + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); stage.show(); } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/TestApp.java b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/TestApp.java index 0fab7a7b..148ee620 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/TestApp.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/app/serviceRequests/TestApp.java @@ -1,12 +1,24 @@ package edu.wpi.cs3733.c20.teamS.app.serviceRequests; +import edu.wpi.cs3733.c20.teamS.database.DatabaseController; +import edu.wpi.cs3733.c20.teamS.database.EmployeeData; +import edu.wpi.cs3733.c20.teamS.database.ServiceData; import javafx.application.Application; import javafx.stage.Stage; -//public class TestApp extends Application { -//// @Override -//// public void start(Stage primaryStage) throws Exception { -//// RideRequestScreen.showDialog(primaryStage) -//// .subscribe(next -> System.out.println(next.result() + " result!")); -//// } -//} +public class TestApp extends Application { + @Override + public void start(Stage primaryStage) throws Exception { +// RideRequestScreen.showDialog(primaryStage) +// .subscribe(next -> System.out.println(next.result() + " result!")); + DatabaseController dbController = new DatabaseController(); + dbController.importStartUpData(); + //Adding ServiceRequests +// ServiceData testService1 = new ServiceData("MTNC", "ASSIGNED", "Good Morning", +// null, 2, null); + ServiceData testService1 = new ServiceData("MTNC", "CREATED", "Good Morning", + null, 0, null); + dbController.addServiceRequestData(testService1); + ActiveServiceRequestScreen.showDialog(); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/applicationInitializer/ApplicationInitializer.java b/src/main/java/edu/wpi/cs3733/c20/teamS/applicationInitializer/ApplicationInitializer.java index 01e88ebd..459bb8bb 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/applicationInitializer/ApplicationInitializer.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/applicationInitializer/ApplicationInitializer.java @@ -4,10 +4,16 @@ import com.google.common.graph.GraphBuilder; import com.google.common.graph.MutableGraph; +import edu.wpi.cs3733.c20.teamS.Editing.EditScreenController; +import edu.wpi.cs3733.c20.teamS.MainStartScreenController; +import edu.wpi.cs3733.c20.teamS.Settings; +import edu.wpi.cs3733.c20.teamS.database.DatabaseController; import edu.wpi.cs3733.c20.teamS.database.EdgeData; import edu.wpi.cs3733.c20.teamS.database.NodeData; -import edu.wpi.cs3733.c20.teamS.database.DatabaseController; +import edu.wpi.cs3733.c20.teamS.pathDisplaying.MainScreenController; +import javafx.fxml.FXMLLoader; +import java.io.IOException; import java.util.Set; import static edu.wpi.cs3733.c20.teamS.ThrowHelper.illegalNull; @@ -28,6 +34,8 @@ public ApplicationInitializer(DatabaseController controller){ } this.controller = controller; this.graph = GraphBuilder.undirected().allowsSelfLoops(true).build(); + //SerialPoller.initSensor(); + } public MutableGraph graph(){ @@ -46,43 +54,6 @@ public void setDatabaseController(DatabaseController controller){ this.controller = controller; } - /** - * Helper Method - * Convert NodeData to GraphNode - * @param nodeData The NodeData to be converted - * @return A GraphNode after conversion - */ - /* - public static GraphNode toGraphNode(NodeData nodeData){ - if(nodeData == null){ - illegalNull("NodeData"); - } - GraphNode graphNode = new GraphNode(nodeData.getNodeID(), nodeData.getxCoordinate(), - nodeData.getyCoordinate(), nodeData.getFloor(), nodeData.getBuilding(), - nodeData.getNodeType(), nodeData.getLongName(), nodeData.getShortName()); - return graphNode; - } - */ - - /** - * Convert a set of NodeData to a set of GraphNode - * @param nodes A set of NodeData to be converted - * @return A set of GraphNodes after conversion - */ - /* - public Set toSetGraphNode(Set nodes){ - if (nodes == null){ - illegalNull("Set of NodeData"); - } - Set graphNodes = new HashSet<>(); - for(NodeData node : nodes){ - GraphNode graphNode = this.toGraphNode(node); - graphNodes.add(graphNode); - } - return graphNodes; - } - */ - /** * Add Nodes to graph * @param allNodeData A set of NodeData to be added @@ -150,4 +121,62 @@ public void run(){ this.addNodesToGraph(allNodeData, this.graph); this.addEdgesToGraph(allEdgeData, this.graph); } + + public void initBigFXMLs(){ + Settings set = Settings.get(); + set.getPrimaryStage().setFullScreen(true); + + initSplashScreen(); + initMainScreen(); + initEmployeeScreen(); + } + + private void initMainScreen(){ + FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/UI_client.fxml")); + loader.setControllerFactory(c ->{ MainScreenController msc = new MainScreenController(Settings.get().getPrimaryStage()); + Settings.get().setMainScreenController(msc); + return Settings.get().getMainScreenController(); + + }); + + try{ + Settings.get().setMainScreenRoot(loader.load()); + } + catch(IOException e){ + System.out.println(e.getMessage()); + throw new RuntimeException(); + } + } + private void initSplashScreen(){ + FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/SplashScreen.fxml")); + loader.setControllerFactory(c -> { + MainStartScreenController cont = new MainStartScreenController(); + return cont; + }); + + try{ + Settings.get().setSplashRoot(loader.load()); + } + catch(IOException e) { + System.out.println(e.getMessage()); + throw new RuntimeException(e); + } + } + private void initEmployeeScreen() { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/UI_employee.fxml")); + + loader.setControllerFactory(c -> { EditScreenController msc = new EditScreenController(); + Settings.get().setEditScreenController(msc); + return Settings.get().getEditScreenController(); + + }); + + try{ + Settings.get().setEmployeeRoot(loader.load()); + } + catch(IOException e){ + System.out.println(e.getMessage()); + throw new RuntimeException(); + } + } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/collisionMasks/HitboxParser.java b/src/main/java/edu/wpi/cs3733/c20/teamS/collisionMasks/HitboxParser.java index 9028a09d..587e85de 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/collisionMasks/HitboxParser.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/collisionMasks/HitboxParser.java @@ -1,6 +1,6 @@ package edu.wpi.cs3733.c20.teamS.collisionMasks; -import edu.wpi.cs3733.c20.teamS.utilities.Vector2; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Vector2; import java.util.*; import java.util.stream.Collectors; @@ -24,6 +24,9 @@ public List parse(Iterable lines) { case 4: result.add(parseFourLineFormat(iter)); break; + case 7: + result.add(parseSevenLineFormat(iter)); + break; default: throw new RuntimeException("Unexpected number of lines per hitbox file format."); } @@ -32,7 +35,35 @@ public List parse(Iterable lines) { return result; } - public List save(Iterable hitboxes) { + public List save(Iterable rooms) { + Stream lines = StreamSupport.stream(rooms.spliterator(), false) + .map(this::saveSingleRoom) + .flatMap(Collection::stream); + return Stream.concat(Stream.of("7"), lines) + .collect(Collectors.toList()); + } + + private List saveSingleRoom(Room room) { + List result = new ArrayList<>(); + result.add(room.name()); + result.add(Integer.toString(room.floor())); + result.add(saveVertices(room.vertices())); + result.add(saveTouchingNodes(room.touchingNodes())); + result.add(room.icon()); + result.addAll(saveDescription(room.description())); + + return result; + } + private List saveDescription(String description) { + String[] lines = description.split("[\\r\\n]+"); + List result = new ArrayList<>(); + result.add(Integer.toString(lines.length)); + Collections.addAll(result, lines); + + return result; + } + + public List saveFourLineFormat(Iterable hitboxes) { Stream hitboxLines = StreamSupport.stream(hitboxes.spliterator(), false) .map(hitbox -> Arrays.asList( hitbox.name(), @@ -40,7 +71,7 @@ public List save(Iterable hitboxes) { saveVertices(hitbox.vertices()), saveTouchingNodes(hitbox.touchingNodes()) )) - .flatMap(lines -> lines.stream()); + .flatMap(Collection::stream); return Stream.concat(Stream.of("4"), hitboxLines) .collect(Collectors.toList()); @@ -63,6 +94,20 @@ private Room parseFourLineFormat(Iterator iter) { return room; } + private Room parseSevenLineFormat(Iterator iter) { + Room room = parseFourLineFormat(iter); + room.setIcon(iter.next()); + int descriptionLineCount = Integer.parseInt(iter.next()); + StringBuilder description = new StringBuilder(); + for (int count = 0; count < descriptionLineCount; count++) { + description.append(iter.next()); + description.append("\n"); + } + room.setDescription(description.toString()); + + return room; + } + private String saveVertices(Iterable vertices) { StringBuilder sb = new StringBuilder(); for (Vector2 vertex : vertices) { diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/collisionMasks/Room.java b/src/main/java/edu/wpi/cs3733/c20/teamS/collisionMasks/Room.java index c62f5573..9ab0f91d 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/collisionMasks/Room.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/collisionMasks/Room.java @@ -1,18 +1,22 @@ package edu.wpi.cs3733.c20.teamS.collisionMasks; -import edu.wpi.cs3733.c20.teamS.database.NodeData; -import edu.wpi.cs3733.c20.teamS.utilities.Vector2; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Vector2; +import edu.wpi.cs3733.c20.teamS.utilities.rx.ReactiveProperty; +import io.reactivex.rxjava3.core.Observable; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.collections.ObservableSet; import javafx.scene.shape.Polygon; -import java.util.ArrayList; + import java.util.HashSet; -import java.util.List; -import java.util.Set; public final class Room { private int floor; - private String name = ""; - private final ArrayList vertices = new ArrayList<>(); - private final HashSet touchingNodes = new HashSet<>(); + private final ReactiveProperty name = new ReactiveProperty<>(""); + private final ReactiveProperty description = new ReactiveProperty<>(""); + private final ReactiveProperty icon = new ReactiveProperty<>(""); + private final ObservableList vertices = FXCollections.observableArrayList(); + private final ObservableSet touchingNodes = FXCollections.observableSet(new HashSet<>()); public Room() {} public Room(int floor) { @@ -25,6 +29,11 @@ public Polygon toPolygon() { return result; } + public Vector2 centroid() { + return vertices.stream() + .reduce(Vector2.ZERO, Vector2::add) + .divide(vertices.size()); + } public int floor() { return floor; } @@ -32,43 +41,47 @@ public void setFloor(int value) { floor = value; } public String name() { - return name; + return name.value(); } public void setName(String value) { - name = value; + name.setValue(value); } - public List vertices() { - return vertices; + public Observable nameChanged() { + return name.changed(); } - public Set touchingNodes() { - return touchingNodes; + public String description() { + return description.value(); + } + public void setDescription(String value) { + description.setValue(value); + } + public Observable descriptionChanged() { + return description.changed(); } - public Vector2 firstVertex() { - return vertices.get(0); + public String icon() { + return icon.value(); } - public void setFirstVertex(Vector2 value) { - vertices.set(0, value); + public void setIcon(String value) { + icon.setValue(value); } - public void setFirstVertex(double x, double y) { - setFirstVertex(new Vector2(x, y)); + public Observable iconChanged() { + return icon.changed(); } - public Vector2 lastVertex() { - return vertices.get(vertices.size() - 1); + public ObservableList vertices() { + return vertices; + } + public ObservableSet touchingNodes() { + return touchingNodes; } + public void setLastVertex(Vector2 value) { vertices.set(vertices.size() - 1, value); } public void setLastVertex(double x, double y) { setLastVertex(new Vector2(x, y)); } - public void setOrAddLastVertex(Vector2 value) { - if (vertices.isEmpty()) { - vertices.add(value); - return; - } - setLastVertex(value); - } - public void setOrAddLastVertex(double x, double y) { - setOrAddLastVertex(new Vector2(x, y)); + + @Override public String toString() { + return name(); } } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/database/DBRepo.java b/src/main/java/edu/wpi/cs3733/c20/teamS/database/DBRepo.java index 631afe00..c058e36e 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/database/DBRepo.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/database/DBRepo.java @@ -39,4 +39,8 @@ public interface DBRepo { Set getEmployeeCapabilities(int employeeID); void removeEmployeeCapabilities(int employeeID); + + EmployeeData getEmployeeFromID(int id); + + Set getAllServiceRequestData(); } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/database/DatabaseController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/database/DatabaseController.java index 5aa05d3c..7bd6aae1 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/database/DatabaseController.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/database/DatabaseController.java @@ -5,7 +5,7 @@ import com.google.common.graph.GraphBuilder; import com.google.common.graph.MutableGraph; import edu.wpi.cs3733.c20.teamS.ThrowHelper; -import edu.wpi.cs3733.c20.teamS.utilities.Numerics; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Numerics; import java.sql.Connection; import java.sql.Date; @@ -100,7 +100,7 @@ private static void dropExistingTables() { System.out.println("EDGES WAS NOT DROPPED"); } - System.out.println("Dropped Table Edges"); + //System.out.println("Dropped Table Edges"); try{ @@ -110,7 +110,7 @@ private static void dropExistingTables() { System.out.println("SERVICES WAS NOT DROPPED"); } - System.out.println("Dropped Table SERVICES"); + //System.out.println("Dropped Table SERVICES"); try{ Statement stm = connection.createStatement(); @@ -119,7 +119,7 @@ private static void dropExistingTables() { System.out.println("NODES WAS NOT DROPPED"); } - System.out.println("Dropped Table Nodes"); + //System.out.println("Dropped Table Nodes"); try{ @@ -129,7 +129,7 @@ private static void dropExistingTables() { System.out.println("SERVICEABLE WAS NOT DROPPED"); } - System.out.println("Dropped Table SERVICEABLE"); + //System.out.println("Dropped Table SERVICEABLE"); try{ Statement stm = connection.createStatement(); @@ -138,7 +138,7 @@ private static void dropExistingTables() { System.out.println("EMPLOYEES WAS NOT DROPPED"); } - System.out.println("Dropped Table EMPLOYEES"); + //System.out.println("Dropped Table EMPLOYEES"); } private static void createServicesTable(Statement stm) throws SQLException { stm.execute("CREATE TABLE SERVICES(" + @@ -150,14 +150,14 @@ private static void createServicesTable(Statement stm) throws SQLException { "assignedEmployee INTEGER CONSTRAINT fKey_empAssigned references EMPLOYEES (employeeID)," + "timeCreated DATE," + "location varchar(1024))"); - System.out.println("Created Table SERVICES"); + //System.out.println("Created Table SERVICES"); } private static void createServiceableTable(Statement stm) throws SQLException { stm.execute("CREATE TABLE SERVICEABLE(" + "employeeID INTEGER CONSTRAINT fKey_service references EMPLOYEES(employeeID)," + "serviceType varchar(4)," + "constraint pKey_canDO primary key (employeeID, serviceType))"); - System.out.println("Created Table SERVICEABLE"); + //System.out.println("Created Table SERVICEABLE"); } private static void createEmployeeTable(Statement stm) throws SQLException { stm.execute("CREATE TABLE EMPLOYEES(" + @@ -168,14 +168,14 @@ private static void createEmployeeTable(Statement stm) throws SQLException { "firstName varchar(30)," + "lastName varchar(30)," + "phoneNumber varchar(11))"); - System.out.println("Created Table Employees"); + //System.out.println("Created Table Employees"); } private static void createEdgeTable(Statement stm) throws SQLException { stm.execute("CREATE TABLE EDGES(" + "edgeID varchar(1024) constraint pKey_edgeID PRIMARY KEY," + "startNode varchar(1024) constraint fKey_startNodeID references NODES (nodeID) ON DELETE CASCADE," + "endNode varchar(1024) constraint fkey_endNodeID references NODES (nodeID) ON DELETE CASCADE)"); - System.out.println("Created Table Edges"); + //System.out.println("Created Table Edges"); } private static void createNodesTable(Statement stm) throws SQLException { stm.execute("CREATE TABLE NODES(" + @@ -188,7 +188,7 @@ private static void createNodesTable(Statement stm) throws SQLException { "longName varchar(1024)," + "shortName varchar(50)," + "constraint pkey_nodeID Primary Key (nodeID))"); - System.out.println("Created Table Nodes"); + //System.out.println("Created Table Nodes"); } /** @@ -324,7 +324,7 @@ public Set getAllNodes(){ public Set getAllNodesOfType(String type){ PreparedStatement stm = null; String allNodeString = "SELECT * FROM Nodes WHERE NODETYPE = ?"; - System.out.println("Getting nodes of type: " + type); + //System.out.println("Getting nodes of type: " + type); try{ stm = connection.prepareStatement(allNodeString); stm.setString(1,type); @@ -769,7 +769,8 @@ public void addServiceRequestData(ServiceData sd) { addStm.setString(2,sd.getStatus()); addStm.setString(3,sd.getMessage()); addStm.setString(4,sd.getData()); - addStm.setInt(5,sd.getAssignedEmployeeID()); + //addStm.setInt(5,sd.getAssignedEmployeeID()); + addStm.setNull(5,Types.VARCHAR); addStm.setDate(6,currentDate); addStm.setString(7,sd.getServiceNode()); addStm.execute(); @@ -1003,7 +1004,7 @@ private void importNodes(){ while(line != null){ String[] lineArray = line.split(",",-1); NodeData node = new NodeData(lineArray[0],Double.parseDouble(lineArray[1]),Double.parseDouble(lineArray[2]),Integer.parseInt(lineArray[3]),lineArray[4],lineArray[5],lineArray[6],lineArray[7]); - System.out.println(node.toString()); + //System.out.println(node.toString()); addNode(node); line = br.readLine(); } @@ -1029,7 +1030,7 @@ private void importEdges(){ while(line != null){ String[] lineArray = line.split(",",-1); EdgeData edge = new EdgeData(lineArray[0],lineArray[1],lineArray[2]); - System.out.println(edge.toString()); + //System.out.println(edge.toString()); addEdge(edge); line = br.readLine(); } @@ -1054,7 +1055,7 @@ private void importEmployees(){ while(line != null){ String[] lineArray = line.split(",",-1); EmployeeData emp = new EmployeeData(lineArray[1],lineArray[2],Integer.parseInt(lineArray[3]),lineArray[4],lineArray[5],lineArray[6]); - System.out.println(emp.toString()); + //System.out.println(emp.toString()); addEmployee(emp); line = br.readLine(); } @@ -1079,7 +1080,7 @@ private void importServiceables(){ line = br.readLine(); while(line != null){ String[] lineArray = line.split(",",-1); - System.out.println("Adding Capability: " + lineArray[1] + " " + "To Employee: " + lineArray[0]); + //System.out.println("Adding Capability: " + lineArray[1] + " " + "To Employee: " + lineArray[0]); addCapability(Integer.parseInt(lineArray[0]), lineArray[1]); line = br.readLine(); } @@ -1121,7 +1122,7 @@ public void removeEmployeeCapabilities(int employeeID){ System.out.println("Failed to remove Capabilities of Employee " + Integer.toString(employeeID)); throw new RuntimeException(); } - System.out.println("Successfully removed Capabilities of Employee " + Integer.toString(employeeID)); + //System.out.println("Successfully removed Capabilities of Employee " + Integer.toString(employeeID)); } public Set getCapableEmployees(String serviceType){ @@ -1168,7 +1169,7 @@ public void removeCapability(int ID, String serviceType){ System.out.println("Failed to remove " + serviceType + "Capability of Employee " + Integer.toString(ID)); throw new RuntimeException(); } - System.out.println("Successfully removed " + serviceType + "Capability of Employee" + Integer.toString(ID)); + //System.out.println("Successfully removed " + serviceType + "Capability of Employee" + Integer.toString(ID)); } public boolean checkCapable(int ID, String serviceType){ diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/database/NodeData.java b/src/main/java/edu/wpi/cs3733/c20/teamS/database/NodeData.java index ff2f391f..4e1274b5 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/database/NodeData.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/database/NodeData.java @@ -7,7 +7,6 @@ import javafx.geometry.Point2D; import java.security.SecureRandom; -import java.util.Objects; public class NodeData { private final PublishSubject positionChanged = PublishSubject.create(); @@ -41,33 +40,10 @@ public NodeData() { this.nodeID = nextUniqueID(); } - - //Getters and setters. - public String getNodeID() { return nodeID; } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - NodeData nodeData = (NodeData) o; - return Double.compare(nodeData.xCoordinate, xCoordinate) == 0 && - Double.compare(nodeData.yCoordinate, yCoordinate) == 0 && - floor == nodeData.floor && - Objects.equals(nodeID, nodeData.nodeID) && - Objects.equals(building, nodeData.building) && - Objects.equals(nodeType, nodeData.nodeType) && - Objects.equals(longName, nodeData.longName) && - Objects.equals(shortName, nodeData.shortName); - } - - @Override - public int hashCode() { - return Objects.hash(nodeID, xCoordinate, yCoordinate, floor, building, nodeType, longName, shortName); - } - @Override public String toString() { return "NodeData{" + diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/emergency/EmergencyController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/emergency/EmergencyController.java new file mode 100644 index 00000000..e0c12d94 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/emergency/EmergencyController.java @@ -0,0 +1,38 @@ +package edu.wpi.cs3733.c20.teamS.emergency; + +import com.jfoenix.controls.JFXButton; +import edu.wpi.cs3733.c20.teamS.MainToLoginScreen; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ScrollPane; +import javafx.scene.image.ImageView; +import javafx.stage.Stage; + +public class EmergencyController { + + @FXML private ImageView mapDisplay; + @FXML private ScrollPane mapScroll; + @FXML private Button exitEmergencyMode; + @FXML private ImageView alertScrolling; + private Stage stage; + + /** + * Creates a Controller for the Emergency Screen + * @param stage The stage to replace + */ + public EmergencyController(Stage stage){ + if (stage == null) ThrowHelper.illegalNull("stage"); + this.stage = stage; + } + + @FXML + Button onBackClicked; + + @FXML + public void onBackClicked(ActionEvent event) { + MainToLoginScreen screen = new MainToLoginScreen(); + + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/emergency/EmergencyScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/emergency/EmergencyScreen.java new file mode 100644 index 00000000..883d9c97 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/emergency/EmergencyScreen.java @@ -0,0 +1,46 @@ +package edu.wpi.cs3733.c20.teamS.emergency; + +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Stage; + +import java.io.IOException; + +public class EmergencyScreen { + + private Scene scene; + + public EmergencyScreen(){ + FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/EmergencyAlert.fxml")); + loader.setControllerFactory(c -> { + EmergencyController controller = new EmergencyController(Settings.get().getPrimaryStage()); + return controller; + }); + try { + Parent root = loader.load(); + if(this.scene == null){ + this.scene = new Scene(root); + } + else{ + this.scene.setRoot(root); + } + + } + catch ( + IOException ex) { + throw new RuntimeException(ex); + } + + this.show(); + } + + public void show() { + Settings.get().getPrimaryStage().setScene(scene); + Settings.get().getPrimaryStage().show(); + //BaseScreen.fireWatch.pause(); + Settings.get().getPrimaryStage().setFullScreen(true); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/loginScreenController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/loginScreenController.java index b27d6125..f33ea413 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/loginScreenController.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/loginScreenController.java @@ -55,23 +55,10 @@ public class loginScreenController { EmployeeData ed = dc.getEmployee(id.getText()); -// FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/TwoFactorScreen.fxml")); -// TwoFactorScreenController twoFac = new TwoFactorScreenController(); -// loader.setController(twoFac); -// twoFac.ed = ed; -// twoFac.dialogCompleted_ = dialogCompleted_; -// //Parent root = loader.load(); -//// //AnchorPane twoFactor = FXMLLoader.load(); -// anchor.getChildren().setAll(); -// anchor.getScene().getWindow().setHeight(313); -// anchor.getScene().getWindow().setWidth(438); - - - - AccessLevel[] al = AccessLevel.values(); AccessLevel accessLevel = al[ed.getAccessLevel()]; Employee emp = new Employee(ed.getEmployeeID(), ed.getFirstName()+ " " + ed.getLastName(), accessLevel); + Settings.get().setLoggedIn(emp); dialogCompleted_.onNext(DialogEvent.ok(emp)); } else { diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/Floor.java b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/Floor.java index 998e26bc..ce182166 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/Floor.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/Floor.java @@ -3,7 +3,7 @@ import com.jfoenix.controls.JFXButton; import javafx.scene.image.Image; -class Floor { +public class Floor { public final Image image; public final JFXButton button; diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/FloorSelector.java b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/FloorSelector.java index 7aba7761..61fdf1b6 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/FloorSelector.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/FloorSelector.java @@ -5,14 +5,14 @@ import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; -class FloorSelector { +public class FloorSelector { private final JFXButton upButton; private final JFXButton downButton; private final Floor[] floors; private final PublishSubject currentChanged = PublishSubject.create(); private int current; - private static final String UNSELECTED_BUTTON_STYLE = "-fx-background-color: #ffffff; -fx-font: 22 System; -fx-text-fill: black;"; - private static final String SELECTED_BUTTON_STYLE = "-fx-background-color: #0067b1; -fx-font: 32 System; -fx-text-fill: white;"; + private static final String UNSELECTED_BUTTON_STYLE = "-fx-background-color: #ffffff; -fx-font: 22 System; -fx-text-fill: black; -fx-background-radius: 5; -fx-border-radius: 5;"; + private static final String SELECTED_BUTTON_STYLE = "-fx-background-color: #0067b1; -fx-font: 32 System; -fx-text-fill: white; -fx-background-radius: 5; -fx-border-radius: 5;"; private final int lowestFloorNumber = 1; private final int highestFloorNumber; diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/MainScreenController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/MainScreenController.java index cd86d69c..3cb7322f 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/MainScreenController.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/MainScreenController.java @@ -1,23 +1,27 @@ package edu.wpi.cs3733.c20.teamS.pathDisplaying; +import animatefx.animation.Pulse; import com.google.common.graph.MutableGraph; import com.jfoenix.controls.JFXButton; -import edu.wpi.cs3733.c20.teamS.LoginScreen; -import edu.wpi.cs3733.c20.teamS.SendTextDirectionsScreen; -import edu.wpi.cs3733.c20.teamS.ThrowHelper; -import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import com.sun.javafx.css.StyleManager; +import edu.wpi.cs3733.c20.teamS.*; import edu.wpi.cs3733.c20.teamS.collisionMasks.HitboxRepository; import edu.wpi.cs3733.c20.teamS.collisionMasks.ResourceFolderHitboxRepository; +import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import edu.wpi.cs3733.c20.teamS.database.DatabaseController; import edu.wpi.cs3733.c20.teamS.database.NodeData; -import edu.wpi.cs3733.c20.teamS.database.*; +import edu.wpi.cs3733.c20.teamS.pathDisplaying.viewModels.RoomDisplayVm; import edu.wpi.cs3733.c20.teamS.pathfinding.IPathfinder; -import edu.wpi.cs3733.c20.teamS.Settings; +import edu.wpi.cs3733.c20.teamS.pathfinding.Path; import edu.wpi.cs3733.c20.teamS.pathfinding.WrittenInstructions; -import edu.wpi.cs3733.c20.teamS.utilities.Vector2; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Vector2; +import edu.wpi.cs3733.c20.teamS.utilities.rx.RxAdaptors; import edu.wpi.cs3733.c20.teamS.widgets.AutoComplete; import edu.wpi.cs3733.c20.teamS.widgets.LookupResult; +import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javafx.event.Event; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; @@ -25,43 +29,46 @@ import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.*; +import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.paint.Color; -import javafx.scene.shape.Polygon; +import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.stage.Modality; import javafx.stage.Stage; -import javafx.scene.layout.VBox; +import javafx.util.StringConverter; -import javax.xml.crypto.Data; import java.io.IOException; import java.net.URL; import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; public class MainScreenController implements Initializable { //region fields private Stage stage; - //private IPathfinder pathfinder; private PathRenderer renderer; private NodeSelector nodeSelector; private MapZoomer zoomer; - private FloorSelector floorSelector; + public static FloorSelector floorSelector; private MutableGraph graph; private final Group group = new Group(); private final HitboxRepository hitboxRepo = new ResourceFolderHitboxRepository(); private final Set rooms = new HashSet<>(); + private final Image Ra = new Image("images/Icons/DarkMode_Sun.png", 160, 160, false, true); + private final Image Khons = new Image("images/Icons/DarkMode_Moon.png", 160, 160, false, true); private boolean flip = true; + private boolean darkmode = false; //endregion public MainScreenController(Stage stage){ if (stage == null) ThrowHelper.illegalNull("stage"); - this.stage = stage; } + @Override public void initialize(URL location, ResourceBundle resources) { - zoomer = new MapZoomer(scrollPane); + zoomer = new MapZoomer(scrollPane, Settings.get().minZoomStage(), Settings.get().maxZoomStage()); initGraph(); renderer = new PathRenderer(); initFloorSelector(); @@ -69,13 +76,20 @@ public void initialize(URL location, ResourceBundle resources) { initHitboxes(); initDirectorySidebar(); initSearchComboBox(); + initDirectoryPathfinding(); scrollPane.setContent(group); - try { - redraw(); - } catch (Exception e) { - e.printStackTrace(); - } + while (zoomer.canZoomOut()) + zoomer.zoomOut(); + redraw(); + } + + public void clearPathDisplay() { + nodeSelector.reset(); + } + + public void setDirectVisible(){ + this.directoryVBox.setVisible(true); } private void initDirectorySidebar() { @@ -88,12 +102,11 @@ private void initDirectorySidebar() { popConfList(); popExitList(); } - private void initNodeSelector() { nodeSelector = new NodeSelector(graph, pathfinder(), () -> floorSelector.current()); nodeSelector.pathChanged().subscribe(path -> { redraw(); - renderer.printInstructions(path, instructionVBox, directoryVBox); + renderer.printInstructions(path, instructionVBox, directoryVBox, darkmode); }); nodeSelector.startChanged() .subscribe(pin -> { @@ -106,7 +119,6 @@ private void initNodeSelector() { location2.setText(text); }); } - private void initHitboxes() { rooms.addAll(hitboxRepo.load()); } @@ -121,7 +133,9 @@ private void initFloorSelector() { new Floor(floorButton2, "images/Floors/HospitalFloor2.png"), new Floor(floorButton3, "images/Floors/HospitalFloor3.png"), new Floor(floorButton4, "images/Floors/HospitalFloor4.png"), - new Floor(floorButton5, "images/Floors/HospitalFloor5.png") + new Floor(floorButton5, "images/Floors/HospitalFloor5.png"), + new Floor(floorButton6, "images/Floors/HospitalFloor6.png"), + new Floor(floorButton7, "images/Floors/HospitalFloor7.png") ); floorSelector.setCurrent(2); floorSelector.currentChanged().subscribe(e -> redraw()); @@ -131,24 +145,44 @@ private void initSearchComboBox() { Font font = new Font(fontFamily, 18); searchComboBox.getEditor().setFont(font); + AutoComplete.start(rooms, searchComboBox, Room::name); + AutoComplete.propertyStream(searchComboBox.valueProperty()) + .filter(result -> result.value() != null) .subscribe(result -> { Room room = result.value(); Vector2 centroid = room.vertices().stream() .reduce(new Vector2(0, 0), Vector2::add) .divide(Math.max(1, room.vertices().size())); floorSelector.setCurrent(room.floor()); - nodeSelector.onHitboxClicked(room, centroid.x(), centroid.y()); + nodeSelector.onRoomClicked(room, centroid.x(), centroid.y()); + }); + searchComboBox.setConverter( + new StringConverter>() { + @Override + public String toString(LookupResult object) { + if (object == null) + return ""; + return object.text(); + } + + @Override + public LookupResult fromString(String string) { + Optional> result = searchComboBox.getItems().stream() + .filter(item -> item.text().equals(string)) + .findFirst(); + return result.orElseGet(() -> new LookupResult<>(string, null)); + } }); - } + } private IPathfinder pathfinder() { return Settings.get().pathfinder(); } - private void redraw() throws Exception { + private void redraw() { double currentHval = scrollPane.getHvalue(); double currentVval = scrollPane.getVvalue(); @@ -166,38 +200,104 @@ private void redraw() throws Exception { .map(this::createHitboxRenderingMask) .forEach(polygon -> group.getChildren().add(polygon)); - keepCurrentPosition(currentHval, currentVval, zoomer); + maintainScrollPosition(currentHval, currentVval); + } + private void maintainScrollPosition(double currentHval, double currentVval) { + int nodesOnFloor = (int)StreamSupport.stream(nodeSelector.path().spliterator(), false) + .filter(node -> node.getFloor() == floorSelector.current()) + .count(); + + if (nodesOnFloor == 0) + keepCurrentPosition(currentHval, currentVval, zoomer); + else { + Vector2 centroid = findPathCentroid(nodeSelector.path(), floorSelector.current()); + double hval = centroid.x() / scrollPane.getContent().getBoundsInLocal().getWidth(); + double vval = centroid.y() / scrollPane.getContent().getBoundsInLocal().getHeight(); + //0.5 is hardcoded offset to fix centering + keepCurrentPosition(hval+0.5, vval, zoomer); + } } - - private Polygon createHitboxRenderingMask(Room room) { - Color visible = Color.AQUA.deriveColor(1, 1, 1, 0.5); - Color invisible = Color.AQUA.deriveColor(1, 1, 1, 0); - Polygon polygon = room.toPolygon(); - polygon.setTranslateY(-10); - polygon.setFill(invisible); - polygon.setOnMouseEntered(e -> polygon.setFill(visible)); - polygon.setOnMouseExited(e -> polygon.setFill(invisible)); - polygon.setOnMouseClicked(e -> nodeSelector.onHitboxClicked(room, e.getX(), e.getY())); - return polygon; + private Vector2 findPathCentroid(Path path, int floor) { + List vertices = path.startToFinish().stream() + .filter(node -> node.getFloor() == floor) + .map(node -> new Vector2(node.getxCoordinate(), node.getyCoordinate())) + .collect(Collectors.toList()); + return vertices.stream() + .reduce(Vector2.ZERO, Vector2::add) + .divide(vertices.size()); + } + private RoomDisplayVm createHitboxRenderingMask(Room room) { + RoomDisplayVm result = new RoomDisplayVm(room); + result.setTranslateY(result.getTranslateY() - 10); + RxAdaptors.eventStream(result::setOnMouseClicked) + .map(e -> result.localToParent(e.getX(), e.getY())) + .subscribe(point -> nodeSelector.onRoomClicked(room, point.getX(), point.getY())); + return result; } - private void keepCurrentPosition(double Hval, double Vval, MapZoomer zoomer){ - zoomer.zoomSet(); + scrollPane.setHvalue(Hval); scrollPane.setVvalue(Vval); + zoomer.zoomSet(); + } + private void initDirectoryPathfinding(){ + deptList.getSelectionModel().selectedItemProperty() + .addListener((a, b, current) -> { + nodeSelector.onNodeClicked(current.value()); + } + ); + + servList.getSelectionModel().selectedItemProperty() + .addListener((a, b, current) -> { + nodeSelector.onNodeClicked(current.value()); + }); + + labList.getSelectionModel().selectedItemProperty() + .addListener((a, b, current) -> { + nodeSelector.onNodeClicked(current.value()); + }); + + infoList.getSelectionModel().selectedItemProperty() + .addListener((a, b, current) -> { + nodeSelector.onNodeClicked(current.value()); + }); + + shopList.getSelectionModel().selectedItemProperty() + .addListener((a, b, current) -> { + nodeSelector.onNodeClicked(current.value()); + }); + + restRoomList.getSelectionModel().selectedItemProperty() + .addListener((a, b, current) -> { + nodeSelector.onNodeClicked(current.value()); + }); + + confList.getSelectionModel().selectedItemProperty() + .addListener((a, b, current) -> { + nodeSelector.onNodeClicked(current.value()); + }); + + exitList.getSelectionModel().selectedItemProperty() + .addListener((a, b, current) -> { + nodeSelector.onNodeClicked(current.value()); + }); } //region ui widgets @FXML private ImageView mapImage; + @FXML private ImageView darkModeImage; @FXML private ScrollPane scrollPane; @FXML private JFXButton floorButton1; @FXML private JFXButton floorButton2; @FXML private JFXButton floorButton3; @FXML private JFXButton floorButton4; @FXML private JFXButton floorButton5; + @FXML private JFXButton floorButton6; + @FXML private JFXButton floorButton7; @FXML private JFXButton downButton; @FXML private JFXButton upButton; @FXML private JFXButton viewThreeD; + @FXML private JFXButton DarkModeButton; @FXML private Label location1; @FXML private VBox instructionVBox; @FXML private VBox directoryVBox; @@ -214,110 +314,87 @@ private void keepCurrentPosition(double Hval, double Vval, MapZoomer zoomer){ @FXML private TitledPane AccCONF; @FXML private TitledPane AccEXIT; - @FXML private ListView deptList; - @FXML private ListView servList; - @FXML private ListView labList; - @FXML private ListView infoList; - @FXML private ListView shopList; - @FXML private ListView restRoomList; - @FXML private ListView confList; - @FXML private ListView exitList; - - - //Lists of longNames - private ObservableList deptLocs; - private ObservableList servLocs; - private ObservableList labLocs; - private ObservableList infoLocs; - private ObservableList shopLocs; - private ObservableList restRoomLocs; - private ObservableList confLocs; - private ObservableList exitLocs; + @FXML private ListView> deptList; + @FXML private ListView> servList; + @FXML private ListView> labList; + @FXML private ListView> infoList; + @FXML private ListView> shopList; + @FXML private ListView> restRoomList; + @FXML private ListView> confList; + @FXML private ListView> exitList; + //endregion + //region Directory Lists private void popDeptList(){ - deptLocs = FXCollections.observableArrayList(); + //region sidebar directory + ObservableList> deptLocs = FXCollections.observableArrayList(); DatabaseController dbController = new DatabaseController(); Set deptNodes = dbController.getAllNodesOfType("DEPT"); for(NodeData node : deptNodes){ - deptLocs.add(node.getLongName() + " At Floor " + Integer.toString(node.getFloor())); - System.out.println("Added " + node + " to depLocs"); + deptLocs.add(new LookupResult<>(node.getLongName(), node)); } deptList.setItems(deptLocs); } - private void popServList(){ - servLocs = FXCollections.observableArrayList(); + ObservableList> servLocs = FXCollections.observableArrayList(); DatabaseController dbController = new DatabaseController(); Set servNodes = dbController.getAllNodesOfType("SERV"); - for(NodeData node : servNodes){ - servLocs.add(node.getLongName() + " At Floor " + Integer.toString(node.getFloor())); - System.out.println("Added " + node + " to servLocs"); + for (NodeData node : servNodes){ + servLocs.add(new LookupResult<>(node.getLongName(), node)); } servList.setItems(servLocs); } - private void popLabList(){ - labLocs = FXCollections.observableArrayList(); + ObservableList> labLocs = FXCollections.observableArrayList(); DatabaseController dbController = new DatabaseController(); Set labNodes = dbController.getAllNodesOfType("LABS"); - for(NodeData node : labNodes){ - labLocs.add(node.getLongName() + " At Floor " + Integer.toString(node.getFloor())); - System.out.println("Added " + node + " to labLocs"); + for (NodeData node : labNodes){ + labLocs.add(new LookupResult<>(node.getLongName(), node)); } labList.setItems(labLocs); } - private void popInfoList(){ - infoLocs = FXCollections.observableArrayList(); + ObservableList> infoLocs = FXCollections.observableArrayList(); DatabaseController dbController = new DatabaseController(); Set infoNodes = dbController.getAllNodesOfType("INFO"); - for(NodeData node : infoNodes){ - infoLocs.add(node.getLongName() + " At Floor " + Integer.toString(node.getFloor())); - System.out.println("Added " + node + " to infoLocs"); + for (NodeData node : infoNodes){ + infoLocs.add(new LookupResult<>(node.getLongName(), node)); } infoList.setItems(infoLocs); } - private void popShopList(){ - shopLocs = FXCollections.observableArrayList(); + ObservableList> shopLocs = FXCollections.observableArrayList(); DatabaseController dbController = new DatabaseController(); Set shopNodes = dbController.getAllNodesOfType("RETL"); - for(NodeData node : shopNodes){ - shopLocs.add(node.getLongName() + " At Floor " + Integer.toString(node.getFloor())); - System.out.println("Added " + node + " to shopLocs"); + for (NodeData node : shopNodes){ + shopLocs.add(new LookupResult<>(node.getLongName(), node)); } shopList.setItems(shopLocs); } - private void popRestRoomList(){ - restRoomLocs = FXCollections.observableArrayList(); + ObservableList> restRoomLocs = FXCollections.observableArrayList(); DatabaseController dbController = new DatabaseController(); Set restRoomNodes = dbController.getAllNodesOfType("REST"); - for(NodeData node : restRoomNodes){ - restRoomLocs.add(node.getLongName() + " At Floor " + Integer.toString(node.getFloor())); - System.out.println("Added " + node + " to restRoomLocs"); + for (NodeData node : restRoomNodes){ + restRoomLocs.add(new LookupResult<>(node.getLongName(), node)); } restRoomList.setItems(restRoomLocs); } - private void popConfList(){ - confLocs = FXCollections.observableArrayList(); + ObservableList> confLocs = FXCollections.observableArrayList(); DatabaseController dbController = new DatabaseController(); Set confNodes = dbController.getAllNodesOfType("CONF"); - for(NodeData node : confNodes){ - confLocs.add(node.getLongName() + " At Floor " + Integer.toString(node.getFloor())); - System.out.println("Added " + node + " to confLocs"); + for (NodeData node : confNodes){ + confLocs.add(new LookupResult<>(node.getLongName(), node)); } confList.setItems(confLocs); } - private void popExitList(){ - exitLocs = FXCollections.observableArrayList(); + ObservableList> exitLocs = FXCollections.observableArrayList(); DatabaseController dbController = new DatabaseController(); Set exitNodes = dbController.getAllNodesOfType("EXIT"); - for(NodeData node : exitNodes){ - exitLocs.add(node.getLongName() + " At Floor " + Integer.toString(node.getFloor())); - System.out.println("Added " + node + " to exitLocs"); + for (NodeData node : exitNodes){ + exitLocs.add(new LookupResult<>(node.getLongName(), node)); } exitList.setItems(exitLocs); } @@ -345,7 +422,18 @@ private void popExitList(){ @FXML private void onFloorClicked5() { floorSelector.setCurrent(5); } - @FXML private void onViewThreeD() throws Exception { ThreeDimensions view = new ThreeDimensions(renderer.getTDnodes());} + @FXML private void onViewThreeD() throws Exception { + if(nodeSelector.goal().isPresent()) { + ThreeDimensions view = new ThreeDimensions(renderer.getTDnodes(), location2.getText(), nodeSelector.goal());} + } + + @FXML private void onFloorClicked6() { + floorSelector.setCurrent(6); + } + @FXML private void onFloorClicked7() { + floorSelector.setCurrent(7); + } + @FXML private void onAboutClicked() { try { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/FXML/AboutMe.fxml")); @@ -356,25 +444,28 @@ private void popExitList(){ window.setFullScreen(false); window.setScene(new Scene(root)); window.setResizable(false); + Settings.openWindows.add(window); + //Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(window.getScene(), Event.ANY); window.show(); } catch (IOException e) { System.out.println("Can't load new window"); } } - @FXML private void onStaffClicked() { LoginScreen.showDialog(this.stage); } - - @FXML private void onSwapButtonPressed() { + //disabled because swap was not needed. + /* @FXML private void onSwapButtonPressed() { String temp = location2.getText(); location2.setText(location1.getText()); location1.setText(temp); - } + } */ @FXML private void onZoomInClicked() { zoomer.zoomIn(); zoomInButton.setDisable(!zoomer.canZoomIn()); zoomOutButton.setDisable(!zoomer.canZoomOut()); + //BaseScreen.puggy.changeTimeout(15000); } @FXML private void onZoomOutClicked() { //Node content = scrollPane.getContent(); @@ -382,10 +473,73 @@ private void popExitList(){ zoomOutButton.setDisable(!zoomer.canZoomOut()); zoomInButton.setDisable(!zoomer.canZoomIn()); } - @FXML private void onTextClicked(){ WrittenInstructions wr = new WrittenInstructions(renderer.getTDnodes()); SendTextDirectionsScreen.showDialog(wr.directions()); } + + @FXML private void onToTextClicked(){ + this.directoryVBox.setVisible(false); + this.instructionVBox.setVisible(true); + } + @FXML private void onToDirectoryClicked(){ + this.instructionVBox.setVisible(false); + this.directoryVBox.setVisible(true); + } + @FXML private void onDarkModeClicked(){ + if (darkmode){ + Application.setUserAgentStylesheet("modena.css"); + StyleManager.getInstance().addUserAgentStylesheet("default.css"); + darkmode = false; + //set image to dark mode button + darkModeImage.setImage(Khons); + System.out.println("returned to light mode"); + } + else { + Application.setUserAgentStylesheet("modena.css"); + StyleManager.getInstance().addUserAgentStylesheet("darkmode.css"); + darkmode = true; + //set image to light mode button + darkModeImage.setImage(Ra); + System.out.println("changed to dark mode"); + } + } + + @FXML private void animate3D() { + new Pulse(viewThreeD).play(); + } + @FXML private void animateFloor1() { + new Pulse(floorButton1).play(); + } + @FXML private void animateFloor2() { + new Pulse(floorButton2).play(); + } + @FXML private void animateFloor3() { + new Pulse(floorButton3).play(); + } + @FXML private void animateFloor4() { + new Pulse(floorButton4).play(); + } + @FXML private void animateFloor5() { + new Pulse(floorButton5).play(); + } + @FXML private void animateFloor6() { + new Pulse(floorButton6).play(); + } + @FXML private void animateFloor7() { + new Pulse(floorButton7).play(); + } + @FXML private void animateFloorDown() { + new Pulse(downButton).play(); + } + @FXML private void animateFloorUp() { + new Pulse(upButton).play(); + } + @FXML private void animateZoomIn() { + new Pulse(zoomInButton).play(); + } + @FXML private void animateZoomOut() { + new Pulse(zoomOutButton).play(); + } //endregion } \ No newline at end of file diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/MapZoomer.java b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/MapZoomer.java index c181c56c..a7bb9818 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/MapZoomer.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/MapZoomer.java @@ -1,7 +1,8 @@ package edu.wpi.cs3733.c20.teamS.pathDisplaying; -import edu.wpi.cs3733.c20.teamS.utilities.Numerics; import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Numerics; +import javafx.scene.Node; import javafx.scene.control.ScrollPane; public class MapZoomer { @@ -21,22 +22,24 @@ public MapZoomer(ScrollPane scrollPane, int minZoomStage, int maxZoomStage) { this.scrollPane = scrollPane; this.minZoomStage = minZoomStage; this.maxZoomStage = maxZoomStage; - zoomStage = Numerics.clamp(-2, minZoomStage, maxZoomStage); + zoomStage = Numerics.clamp(0, minZoomStage, maxZoomStage); } public double zoomFactor() { // Zoom factor is incremented in stages, just like stat-changes in Pokemon. - double result = 1.0 + 0.5 * Math.abs(zoomStage); + // Currently, the stages for Accuracy and Evasion are used, which are equal to 1/3 per stage, as opposed + // to the stages that are used for the other stats, which are equal to 1/2 per stage. + double result = 1.0 + Math.abs(zoomStage) / 3.0; if (zoomStage < 0) { - return 1.0 / result; + result = 1.0 / result; } - return result; } private void updateImageSize() { - scrollPane.getContent().setScaleX(zoomFactor()); - scrollPane.getContent().setScaleY(zoomFactor()); + Node content = scrollPane.getContent(); + content.setScaleX(zoomFactor()); + content.setScaleY(zoomFactor()); } public boolean canZoomIn() { diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/NodeSelector.java b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/NodeSelector.java index 4c61406c..8ccaf2b8 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/NodeSelector.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/NodeSelector.java @@ -6,12 +6,10 @@ import edu.wpi.cs3733.c20.teamS.database.NodeData; import edu.wpi.cs3733.c20.teamS.pathfinding.IPathfinder; import edu.wpi.cs3733.c20.teamS.pathfinding.Path; -import edu.wpi.cs3733.c20.teamS.utilities.ReactiveProperty; +import edu.wpi.cs3733.c20.teamS.utilities.rx.ReactiveProperty; import io.reactivex.rxjava3.core.Observable; -//import sun.reflect.generics.reflectiveObjects.NotImplementedException; import java.util.*; - import java.util.function.IntSupplier; import java.util.stream.Collectors; @@ -42,16 +40,42 @@ public NodeSelector(MutableGraph graph, IPathfinder pathfinder, IntSup state = new NoSelectionState(); } - public void onHitboxClicked(Room room, double x, double y) { + /** + * Call this whenever the user clicks on, or otherwise selects, a room. The value of start, goal, + * and path will be updated appropriately depending on which nodes have been selected so far. + * @param room The room they selected. + * @param x The x-coordinate of the point in the room that was clicked. + * @param y The y-coordinate of the point in the room that was clicked. + */ + public void onRoomClicked(Room room, double x, double y) { + if (room == null) ThrowHelper.illegalNull("room"); + state.onRoomClicked(room, x, y); } + /** + * Call this whenever the user clicks on, or otherwise selects, a node. + * @param node The node that the user selected. + */ + public void onNodeClicked(NodeData node) { + if (node == null) ThrowHelper.illegalNull("node"); + + state.onNodeClicked(node); + } + public void reset() { + start.setValue(Optional.empty()); + goal.setValue(Optional.empty()); + path.setValue(Path.empty()); + } private NodeData createFakeNode(double x, double y) { return new NodeData("FAKE", x, y, floorSupplier.getAsInt(), "NONE", "FAKE", "FAKE NODE", "FAKE NODE"); } + private boolean isNodeFake(NodeData node) { + return node.getNodeID().equals("FAKE"); + } public Path path() { return path.value(); @@ -75,20 +99,36 @@ public Observable> goalChanged() { private abstract class State { public void onRoomClicked(Room room, double x, double y) {} + public void onNodeClicked(NodeData node) {} public final NodeSelector outer() { return NodeSelector.this; } } private final class NoSelectionState extends State { - @Override - public void onRoomClicked(Room room, double x, double y) { + @Override public void onRoomClicked(Room room, double x, double y) { NodeData fakeStart = createFakeNode(x, y); - outer().start.setValue(Optional.of(new PinDrop(room, fakeStart))); + onEndpointClicked(fakeStart, room); + } + @Override public void onNodeClicked(NodeData node) { + Room room = createFakeRoomFromRealNode(node); + room.touchingNodes().add(node.getNodeID()); + onEndpointClicked(node, room); + } + + private void onEndpointClicked(NodeData node, Room room) { + outer().start.setValue(Optional.of(new PinDrop(room, node))); outer().goal.setValue(Optional.empty()); outer().path.setValue(Path.empty()); outer().state = new StartSelectedState(start.value().get()); } } + + private Room createFakeRoomFromRealNode(NodeData node) { + Room room = new Room(); + room.setName(node.getLongName()); + return room; + } + private final class StartSelectedState extends State { private final PinDrop start; @@ -96,10 +136,15 @@ public StartSelectedState(PinDrop start) { this.start = start; } - @Override - public void onRoomClicked(Room room, double x, double y) { + @Override public void onRoomClicked(Room room, double x, double y) { + if (room == null) ThrowHelper.illegalNull("room"); + PinDrop goal = new PinDrop(room, createFakeNode(x, y)); + doMostOfPathfindingShit(goal); + } + + private void doMostOfPathfindingShit(PinDrop goal) { Set realStartNodes = realNodesInHitbox(start.room()); Set realEndNodes = realNodesInHitbox(goal.room()); @@ -109,7 +154,7 @@ public void onRoomClicked(Room room, double x, double y) { ); Path bestPath = results.stream() - .min(Comparator.comparingDouble(p -> p.cost())) + .min(Comparator.comparingDouble(Path::cost)) .orElse(Path.empty()); outer().goal.setValue(Optional.of(goal)); @@ -118,6 +163,16 @@ public void onRoomClicked(Room room, double x, double y) { outer().state = new NoSelectionState(); } + @Override public void onNodeClicked(NodeData node) { + if (node == null) ThrowHelper.illegalNull("node"); + + Room room = createFakeRoomFromRealNode(node); + room.touchingNodes().add(node.getNodeID()); + PinDrop goal = new PinDrop(room, node); + doMostOfPathfindingShit(goal); + //onRoomClicked(room, node.getxCoordinate(), node.getyCoordinate()); + } + private Collection findAllPossiblePaths( NodeData fakeStart, NodeData fakeEnd, Set realStartNodes, @@ -126,7 +181,11 @@ private Collection findAllPossiblePaths( graph.addNode(fakeEnd); List results = new ArrayList<>(); for (NodeData realStart : realStartNodes) { + if (realStart == fakeStart) + continue; for (NodeData realEnd : realEndNodes) { + if (realEnd == fakeEnd) + continue; graph.putEdge(fakeStart, realStart); graph.putEdge(fakeEnd, realEnd); Path path = pathfinder.findPath(graph, fakeStart, fakeEnd); diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/PathRenderer.java b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/PathRenderer.java index d5fb697e..0f6cf20b 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/PathRenderer.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/PathRenderer.java @@ -4,16 +4,18 @@ import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; import edu.wpi.cs3733.c20.teamS.database.NodeData; -//import edu.wpi.cs3733.c20.teamS.pathfinding.Path; import edu.wpi.cs3733.c20.teamS.pathfinding.WrittenInstructions; +import edu.wpi.cs3733.c20.teamS.serviceRequests.SelectServiceScreen; import edu.wpi.cs3733.c20.teamS.utilities.Board; import javafx.animation.PathTransition; import javafx.animation.Timeline; +import javafx.event.EventHandler; import javafx.scene.Group; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -import javafx.scene.paint.Color; import javafx.scene.shape.*; import javafx.scene.text.Font; import javafx.util.Duration; @@ -21,6 +23,8 @@ import java.util.List; import java.util.stream.Collectors; +//import edu.wpi.cs3733.c20.teamS.pathfinding.Path; + class PathRenderer { /** @@ -32,7 +36,7 @@ class PathRenderer { * @return A new Group containing all the elements that were drawn. */ private List TDnodes; - public Group draw(edu.wpi.cs3733.c20.teamS.pathfinding.Path path, int floor) throws Exception { + public Group draw(edu.wpi.cs3733.c20.teamS.pathfinding.Path path, int floor) { if (path == null) ThrowHelper.illegalNull("path"); Group group = new Group(); @@ -60,7 +64,7 @@ public Group draw(edu.wpi.cs3733.c20.teamS.pathfinding.Path path, int floor) thr boolean down = start.getFloor() > end.getFloor(); nodes.stream() .filter(node -> node.getNodeType().equals("ELEV")) - .map(node -> down ? drawDownElevator(node, start, end) : drawUpElevator(node, start, end)) + .map(node -> down ? drawDownElevator(node, start, end, floor) : drawUpElevator(node, start, end, floor)) .forEach(image -> group.getChildren().add(image)); boolean runOnce = true; @@ -69,6 +73,13 @@ public Group draw(edu.wpi.cs3733.c20.teamS.pathfinding.Path path, int floor) thr double X = start.getxCoordinate(); double Y = start.getyCoordinate(); + Image i = new Image("images/Icons/outlined_arrow.png"); + ImageView imageView = new ImageView(); + imageView.setPreserveRatio(true); + imageView.setFitHeight(50); + imageView.setImage(i); + imageView.setVisible(false); + for (NodeData node_itrat : nodes) { if((node_itrat.getFloor() == floor) && runOnce){ animated_path = new Path(); @@ -81,15 +92,10 @@ public Group draw(edu.wpi.cs3733.c20.teamS.pathfinding.Path path, int floor) thr length += Math.sqrt(Math.pow((Math.abs(X - node_itrat.getxCoordinate())), 2) + Math.pow((Math.abs(Y - node_itrat.getyCoordinate())),2)); X = node_itrat.getxCoordinate(); Y = node_itrat.getyCoordinate(); + imageView.setVisible(true); } } - Image i = new Image("images/Icons/outlined_arrow.png"); - ImageView imageView = new ImageView(); - imageView.setPreserveRatio(true); - imageView.setFitHeight(50); - imageView.setImage(i); - PathTransition pathTransition = new PathTransition(); pathTransition.setDuration(Duration.seconds(getPathTime(length))); pathTransition.setPath(animated_path); @@ -99,7 +105,6 @@ public Group draw(edu.wpi.cs3733.c20.teamS.pathfinding.Path path, int floor) thr //pathTransition.setAutoReverse(true); //enable this if you want for reverse for some reason pathTransition.play(); group.getChildren().add(imageView); - //directoryVbox.setVisible(false); return group; } @@ -110,11 +115,12 @@ private double getPathTime(double lengthOfPath){ } /** * Displays the instructions for the specified Path in the specified VBox. - * @param path The path to display instructions for. - * @param directoryBox The VBox to display the directory + * @param path The path to display instructions for. * @param displayBox The VBox to display the instructions in. + * @param directoryBox The VBox to display the directory + * @param darkmode The boolean to show whether darkmode is or not implemented */ - public void printInstructions(edu.wpi.cs3733.c20.teamS.pathfinding.Path path, VBox displayBox, VBox directoryBox) { + public void printInstructions(edu.wpi.cs3733.c20.teamS.pathfinding.Path path, VBox displayBox, VBox directoryBox, boolean darkmode) { if (path == null) ThrowHelper.illegalNull("path"); if (displayBox == null) ThrowHelper.illegalNull("displayBox"); if (directoryBox == null) ThrowHelper.illegalNull("directoryBox"); @@ -122,31 +128,185 @@ public void printInstructions(edu.wpi.cs3733.c20.teamS.pathfinding.Path path, VB List nodes = path.startToFinish(); WrittenInstructions instructionWriter = new WrittenInstructions(nodes); List instructions = instructionWriter.directions(); + if (darkmode){ + displayBox.setStyle("-fx-text-fill: white"); + } + else { + displayBox.setStyle("-fx-text-fill: black"); + } displayBox.getChildren().clear(); - //JFXTextField directionLabel = new JFXTextField(); - //directionLabel.setText("Directions"); - //JFXTextField space = new JFXTextField(); - directoryBox.setVisible(true); - for (String direct : instructions) { + + for (int i = 0; i < instructions.size(); i++) { + HBox imageHolder = new HBox(); JFXTextArea text = new JFXTextArea(); - text.setText(direct); + text.setText(" " + instructions.get(i)); + ImageView image = new ImageView(); + + String word = instructions.get(i).trim(); + + if(word.contains("Left")){ + if (darkmode) { + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/leftTurn2-w.png"))); + image.setImage(newImage); + } + else { + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/leftTurn2.png"))); + image.setImage(newImage); + } + + image.setFitHeight(25); + image.setFitWidth(25); +// image.setX(50); +// image.setY(-20); + image.setTranslateX(30); + image.setTranslateY(4); + + + image.setPreserveRatio(true); + } + else if(word.contains("Right")){ + if (darkmode) { + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/rightTurn2-w.png"))); + image.setImage(newImage); + } + else { + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/rightTurn2.png"))); + image.setImage(newImage); + } + image.setFitHeight(25); + image.setFitWidth(25); + image.setTranslateX(30); + image.setTranslateY(4); + + image.setPreserveRatio(true); + } + else if(word.contains("straight")){ + if (darkmode) { + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/up-straight-arrow-w.png"))); + image.setImage(newImage); + } + else { + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/up-straight-arrow.png"))); + image.setImage(newImage); + } + image.setFitHeight(25); + image.setFitWidth(25); + image.setTranslateX(30); + image.setTranslateY(4); + + image.setPreserveRatio(true); + + } + else if(word.contains("Elevator")){ + if (darkmode) { + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/elevator-2-w.png"))); + image.setImage(newImage); + } + else { + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/elevator-2.png"))); + image.setImage(newImage); + } + image.setFitHeight(25); + image.setFitWidth(25); + image.setTranslateX(28); + image.setTranslateY(5); + image.setPreserveRatio(false); + } + else { + System.out.println("in else statement"); + if(word.contains("Floor 1")){ + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/one.png"))); + image.setImage(newImage); + image.setFitHeight(30); + image.setFitWidth(30); + image.setTranslateX(0); + image.setTranslateY(5); + image.setPreserveRatio(false); + } + if(word.contains("Floor 2")){ + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/two.png"))); + image.setImage(newImage); + image.setFitHeight(30); + image.setFitWidth(30); + image.setTranslateX(00); + image.setTranslateY(5); + image.setPreserveRatio(false); + } + if(word.contains("Floor 3")){ + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/three.png"))); + image.setImage(newImage); + image.setFitHeight(30); + image.setFitWidth(30); + image.setTranslateX(0); + image.setTranslateY(5); + image.setPreserveRatio(false); + } + if(word.contains("Floor 4")){ + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/four.png"))); + image.setImage(newImage); + image.setFitHeight(30); + image.setFitWidth(30); + image.setTranslateX(0); + image.setTranslateY(5); + image.setPreserveRatio(false); + } + if(word.contains("Floor 5")){ + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/five.png"))); + image.setImage(newImage); + image.setFitHeight(30); + image.setFitWidth(30); + image.setTranslateX(0); + image.setTranslateY(5); + image.setPreserveRatio(false); + } + if(word.contains("Floor 6")){ + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/six.png"))); + image.setImage(newImage); + image.setFitHeight(30); + image.setFitWidth(30); + image.setTranslateX(0); + image.setTranslateY(5); + image.setPreserveRatio(false); + } + if(word.contains("Floor 7")){ + Image newImage = new Image(String.valueOf(getClass().getResource("/images/Instructions/seven.png"))); + image.setImage(newImage); + image.setFitHeight(30); + image.setFitWidth(30); + image.setTranslateX(0); + image.setTranslateY(5); + image.setPreserveRatio(false); + } + + } text.setEditable(false); if (text.getLength() > 27){ - text.setFont(Font.font ("System", 15)); - text.setMinHeight(50); - text.setPrefHeight(50); - text.setMaxHeight(200); + text.setFont(Font.font ("System", 11)); + text.setPrefHeight(30); + text.setPrefWidth(150); + text.setTranslateX(35); } - else if (text.getLength() > 24){ - text.setFont(Font.font ("System", 16)); + else if (text.getLength() >= 22){ + text.setFont(Font.font ("System", 11)); text.setPrefHeight(30); + text.setTranslateX(33); + } else { - text.setFont(Font.font ("System", 18)); - text.setPrefHeight(10); + text.setFont(Font.font ("System", 14)); + text.setPrefHeight(30); + //text.setPref + //text.setTranslateX(30); + } - displayBox.getChildren().add(text); + //text.setStyle("-fx-background-color: #ccc"); + imageHolder.getChildren().add(image); + imageHolder.getChildren().add(text); + displayBox.getChildren().add(imageHolder); + + displayBox.setVisible(true); + directoryBox.setVisible(false); } } @@ -209,28 +369,40 @@ private static ImageView drawEndBalloon(NodeData node) { return pinIcon; } - private ImageView drawDownElevator(NodeData node2, NodeData startNode, NodeData endNode) { - if((node2 != startNode) && (node2 != endNode)) { + private ImageView drawDownElevator(NodeData node2, NodeData startNode, NodeData endNode, int floor) { + if((node2 != startNode) && (node2 != endNode) && (node2.getFloor() == floor)) { ImageView elevator_icon_down = new ImageView(); - elevator_icon_down.setImage(new Image("images/Balloons/down_arrow.gif")); - elevator_icon_down.setX(node2.getxCoordinate() - 25); - elevator_icon_down.setY(node2.getyCoordinate() - 20); + elevator_icon_down.setImage(new Image("images/Balloons/greeeeeeeeen.gif")); + elevator_icon_down.setX(node2.getxCoordinate() - 50); + elevator_icon_down.setY(node2.getyCoordinate() - 40); elevator_icon_down.setPreserveRatio(true); - elevator_icon_down.setFitWidth(40); + elevator_icon_down.setFitWidth(80); + elevator_icon_down.setOnMouseClicked(new EventHandler() { + @Override + public void handle(MouseEvent event) { + MainScreenController.floorSelector.setCurrent(endNode.getFloor()); + } + }); return elevator_icon_down; }else return new ImageView(); } - private ImageView drawUpElevator(NodeData node2, NodeData startNode, NodeData endNode) { - if((node2 != startNode) && (node2 != endNode)) { + private ImageView drawUpElevator(NodeData node2, NodeData startNode, NodeData endNode, int floor) { + if((node2 != startNode) && (node2 != endNode && (node2.getFloor() == floor))) { ImageView elevator_icon_up = new ImageView(); - elevator_icon_up.setImage(new Image("images/Balloons/down_arrow.gif")); - elevator_icon_up.setX(node2.getxCoordinate() - 25); - elevator_icon_up.setY(node2.getyCoordinate() - 20); + elevator_icon_up.setImage(new Image("images/Balloons/greeeeeeeeen.gif")); + elevator_icon_up.setX(node2.getxCoordinate() - 50); + elevator_icon_up.setY(node2.getyCoordinate() - 40); elevator_icon_up.setPreserveRatio(true); - elevator_icon_up.setFitWidth(40); + elevator_icon_up.setFitWidth(80); elevator_icon_up.setRotate(180); + elevator_icon_up.setOnMouseClicked(new EventHandler() { + @Override + public void handle(MouseEvent event) { + MainScreenController.floorSelector.setCurrent(endNode.getFloor()); + } + }); return elevator_icon_up; }else return new ImageView(); diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/PinDrop.java b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/PinDrop.java index 676df3ad..d83bf53e 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/PinDrop.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/PinDrop.java @@ -2,7 +2,6 @@ import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; import edu.wpi.cs3733.c20.teamS.database.NodeData; -import edu.wpi.cs3733.c20.teamS.utilities.Vector2; public final class PinDrop { private final Room room; diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/ThreeDimensions.java b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/ThreeDimensions.java index e691ce15..c96373c3 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/ThreeDimensions.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/ThreeDimensions.java @@ -1,30 +1,22 @@ package edu.wpi.cs3733.c20.teamS.pathDisplaying; +import com.interactivemesh.jfx.importer.obj.ObjModelImporter; import com.interactivemesh.jfx.importer.stl.StlMeshImporter; -import com.jfoenix.controls.JFXTextArea; import edu.wpi.cs3733.c20.teamS.database.DatabaseController; -import edu.wpi.cs3733.c20.teamS.database.EdgeData; import edu.wpi.cs3733.c20.teamS.database.NodeData; -import edu.wpi.cs3733.c20.teamS.pathDisplaying.PathRenderer; -import edu.wpi.cs3733.c20.teamS.utilities.Board; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Vector2; import javafx.animation.*; import javafx.application.Application; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.SimpleDoubleProperty; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; import javafx.geometry.Point3D; import javafx.scene.*; import javafx.scene.control.Button; -import javafx.scene.control.Slider; -import javafx.scene.effect.Bloom; -import javafx.scene.effect.DropShadow; -import javafx.scene.effect.Glow; +import javafx.scene.control.Label; import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; +import javafx.scene.input.MouseEvent; import javafx.scene.input.ScrollEvent; +import javafx.scene.layout.AnchorPane; import javafx.scene.paint.Color; import javafx.scene.paint.PhongMaterial; import javafx.scene.shape.*; @@ -32,1037 +24,837 @@ import javafx.scene.transform.Transform; import javafx.scene.transform.Translate; import javafx.stage.Stage; -import javafx.scene.shape.Path; import javafx.util.Duration; -import org.apache.derby.impl.sql.catalog.SYSROUTINEPERMSRowFactory; - import java.io.File; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; +import java.net.URL; +import java.util.*; public class ThreeDimensions extends Application { - private static String MESH_FILENAME = null; - - private static final String STARTICON = - ThreeDimensions.class.getResource("/images/ThreeDim/start.STL").toString(); - private static final String FINISHICON = - ThreeDimensions.class.getResource("/images/ThreeDim/finish.STL").toString(); - - private static final String clarinet = - ThreeDimensions.class.getResource("/images/ThreeDim/Clarinet.stl").toString(); - - private static final String hat = ThreeDimensions.class.getResource("/images/ThreeDim/hat.stl").toString(); - private PathTransition pathTrans; - private List nodes; private Stage primaryStage = new Stage(); - private double cost; + private String goal = ""; + private List goalLine; - public ThreeDimensions(List nodes) throws Exception { - this.nodes = nodes; - start(primaryStage); - } - public static final float WIDTH = 1400; - public static final float HEIGHT = 800; + public ThreeDimensions(List nodes, String goal, Optional goalRoom) throws Exception { + if(goalRoom.isPresent()) { + if(nodes != null) { + goalLine = goalRoom.get().room().vertices(); + this.nodes = nodes; + this.goal = goal; + start(primaryStage); }} + } - private double anchorX, anchorY; - private double anchorAngleX = 0; - private double anchorAngleY = 0; - private final DoubleProperty angleX = new SimpleDoubleProperty(0); - private final DoubleProperty angleY = new SimpleDoubleProperty(0); + private final float WIDTH = 1422; + private final float HEIGHT = 800; + private double oldX, oldY; + private ArrayList floorAddress = new ArrayList<>(); + private boolean elevToggle = true; + private boolean foodToggle = true; + private boolean restToggle = true; + private boolean retlToggle = true; + private boolean staiToggle = true; + private HashMap zplace = new HashMap(); + private final double floorDist = 100; + private ArrayList allFloorsInvolved = new ArrayList<>(); + private final int totalFloors = 7; @Override public void start(Stage primaryStage) throws Exception { - ArrayList anglez = new ArrayList(); - for (int i = 0; i < nodes.size() - 2; i++) { - Point3D one = new Point3D(nodes.get(i).getxCoordinate(), nodes.get(i).getyCoordinate(), 0); - Point3D two = new Point3D(nodes.get(i + 1).getxCoordinate(), nodes.get(i + 1).getyCoordinate(), 0); - Point3D three = new Point3D(nodes.get(i + 2).getxCoordinate(), nodes.get(i + 2).getyCoordinate(), 0); - double angle = calculateAngle(one.getX(), one.getY(), two.getX(), two.getY(), three.getX(), three.getY()); - anglez.add((int) angle); - } - System.out.println(nodes.size()); - System.out.println(anglez.size()); - - SmartGroup group = new SmartGroup(); - if (nodes.get(0).getFloor() == 2 || nodes.get(nodes.size() - 1).getFloor() == 2) { - group.getChildren().add(prepareBox(0)); //second - } else { - group.getChildren().add(prepareBox(1)); - } - if (nodes.get(0).getFloor() == 3 || nodes.get(nodes.size() - 1).getFloor() == 3) { - group.getChildren().add(prepareSecondBox(0)); //third - } else { - group.getChildren().add(prepareSecondBox(1)); - } - if (nodes.get(0).getFloor() == 1 || nodes.get(nodes.size() - 1).getFloor() == 1) { - group.getChildren().add(prepareThirdBox(0)); //first - } else { - group.getChildren().add(prepareThirdBox(1)); - } - if (nodes.get(0).getFloor() == 4 || nodes.get(nodes.size() - 1).getFloor() == 4) { - group.getChildren().add(prepareFourthBox(0)); //fourth - } else { - group.getChildren().add(prepareFourthBox(1)); - } - if (nodes.get(0).getFloor() == 5 || nodes.get(nodes.size() - 1).getFloor() == 5) { - group.getChildren().add(prepareFifthBox(0)); //fifth - } else { - group.getChildren().add(prepareFifthBox(1)); - } - group.getChildren().add(new AmbientLight(Color.WHITE)); - Point3D point1 = new Point3D(0, 0, 0); - Point3D point2 = new Point3D(0, 0, 0); - - Camera camera = new PerspectiveCamera(); - camera.setTranslateY(-50); - - - DatabaseController dbc = new DatabaseController(); - //dbc.importStartUpData(); - Set nd = dbc.getAllNodes(); - - HashMap zplace1 = new HashMap(); - zplace1.put(1, 100); - zplace1.put(2, 0); - zplace1.put(3, -100); - zplace1.put(4, -200); - zplace1.put(5, -300); - - Shape s = new Circle(10); - s.setStrokeWidth(3); - s.setStrokeLineCap(StrokeLineCap.ROUND); - s.setStroke(Color.AQUA); - s.setFill(Color.LIGHTYELLOW); - //s.setEffect(new Bloom()); - s.setTranslateX(nodes.get(nodes.size() - 1).getxCoordinate() / 5 - 247); - s.setTranslateZ(zplace1.get(nodes.get(nodes.size() - 1).getFloor())); - s.setTranslateY(nodes.get(nodes.size() - 1).getyCoordinate() / 5 - 148); - - Box wongBox = new Box(); - wongBox.setHeight(40); - wongBox.setWidth(40); - wongBox.setDepth(40); - PhongMaterial material = new PhongMaterial(); - Image image = new Image(("images/ThreeDim/wwong2.jpg")); - material.setDiffuseMap(image); - wongBox.setMaterial(material); - wongBox.setTranslateZ(-70); - - double total = 0; - double length; - SequentialTransition sequentialTransition = new SequentialTransition(); - for (int i = 0; i < nodes.size() - 1; i++) { - HashMap zplace = new HashMap(); - zplace.put(1, 100); - zplace.put(2, 0); - zplace.put(3, -100); - zplace.put(4, -200); - zplace.put(5, -300); - NodeData startNode = nodes.get(i); - NodeData endNode = nodes.get(i + 1); - int floor1 = startNode.getFloor(); - int floor2 = endNode.getFloor(); - boolean sameFloor = (floor1 == floor2); - - length = Math.sqrt(Math.pow(Math.abs(endNode.getxCoordinate() - startNode.getxCoordinate()), 2) + Math.pow(Math.abs(endNode.getyCoordinate() - startNode.getyCoordinate()), 2)); - TranslateTransition translateTransition = new TranslateTransition(Duration.seconds(getPathTime(length)), wongBox); //can change mph - translateTransition.setFromZ(zplace.get(startNode.getFloor()) - 50 - 30); - translateTransition.setFromX(startNode.getxCoordinate() / 5 - 247); - translateTransition.setFromY(startNode.getyCoordinate() / 5 - 148); - translateTransition.setToZ(zplace.get(endNode.getFloor()) - 50 - 30); - translateTransition.setToX(endNode.getxCoordinate() / 5 - 247); - translateTransition.setToY(endNode.getyCoordinate() / 5 - 148); - translateTransition.setInterpolator(Interpolator.LINEAR); - translateTransition.setCycleCount(1); - total += 1000; - //translateTransition.setAutoReverse(true); - //sequentialTransition.getChildren().add(createTransition(animated_path, wongBox)); - sequentialTransition.getChildren().addAll(translateTransition); - -// if(i+1 < anglez.size()) { -// RotateTransition rt = new RotateTransition(); -// rt.setDuration(Duration.seconds(getPathTime(length))); -// rt.setNode(wongBox); -// rt.setAxis(Rotate.Z_AXIS); -// rt.setCycleCount(1); -// rt.setToAngle(-anglez.get(i)); -// rt.getNode().getTransforms().setAll(new Rotate(-anglez.get(i+1), Rotate.Z_AXIS), new Rotate(0, Rotate.X_AXIS)); -// -// sequentialTransition.getChildren().add(rt); -// } + for(int i = 0; i < nodes.size(); i++) { + if(allFloorsInvolved.contains(nodes.get(i).getFloor()) == false) { + allFloorsInvolved.add(nodes.get(i).getFloor()); + } } - sequentialTransition.setCycleCount(Timeline.INDEFINITE); - //sequentialTransition.setAutoReverse(true); - sequentialTransition.play(); - - double MODEL_SCALE_FACTOR = 4.3; - - String thing = getClass().getResource("/images/ThreeDim/person.stl").toURI().getPath(); - //String thing2 = thing.substring(6).replaceAll("/","\\"); - - - MeshView[] meshViews = loadMeshViews(thing); - for (int i = 0; i < meshViews.length; i++) { -// meshViews[i].setTranslateX(0); -// meshViews[i].setTranslateY(0); -// meshViews[i].setTranslateZ(0); - meshViews[i].setScaleX(MODEL_SCALE_FACTOR); - meshViews[i].setScaleY(MODEL_SCALE_FACTOR); - meshViews[i].setScaleZ(MODEL_SCALE_FACTOR); - - PhongMaterial sample = new PhongMaterial(); - Image image2 = new Image(("images/ThreeDim/gray.jpg")); - sample.setDiffuseMap(image2); - //sample.setSpecularColor(Color.BEIGE); - //sample.setSpecularPower(16); - meshViews[i].setMaterial(sample); - meshViews[i].getTransforms().setAll(new Rotate(0, Rotate.X_AXIS)); - } + zplace.put(1, 100); + zplace.put(2, 0); + zplace.put(3, -100); + zplace.put(4, -200); + zplace.put(5, -300); + zplace.put(6, -400); + zplace.put(7, -500); - String thing2 = getClass().getResource("/images/ThreeDim/start.stl").toURI().getPath(); - int MODEL_SCALE_FACTOR2 = 3; - MeshView[] meshViews2 = loadMeshViews(thing2); - for (int i = 0; i < meshViews2.length; i++) { - HashMap zplace = new HashMap(); - zplace.put(1, 100); - zplace.put(2, 0); - zplace.put(3, -100); - zplace.put(4, -200); - zplace.put(5, -300); - meshViews2[i].setTranslateX((nodes.get(0).getxCoordinate() / 5 - 247) - 100); - meshViews2[i].setTranslateY(nodes.get(0).getyCoordinate() / 5 - 148); - meshViews2[i].setTranslateZ(zplace.get(nodes.get(0).getFloor())); - meshViews2[i].setScaleX(MODEL_SCALE_FACTOR2); - meshViews2[i].setScaleY(MODEL_SCALE_FACTOR2); - meshViews2[i].setScaleZ(MODEL_SCALE_FACTOR2); - - PhongMaterial sample = new PhongMaterial(); - Image image2 = new Image(("images/ThreeDim/space.jpg")); - sample.setDiffuseMap(image2); - //sample.setSpecularColor(Color.BEIGE); - //sample.setSpecularPower(16); - meshViews2[i].setMaterial(sample); - - meshViews2[i].getTransforms().setAll(new Rotate(0, Rotate.Z_AXIS), new Rotate(90, Rotate.X_AXIS)); - } + NodeData begin = nodes.get(0); + NodeData end = nodes.get(nodes.size() - 1); - String thing3 = getClass().getResource("/images/ThreeDim/finish.stl").toURI().getPath(); - - MeshView[] meshViews3 = loadMeshViews(thing3); - double MODEL_SCALE_FACTOR22 = 0.15; - for (int i = 0; i < meshViews3.length; i++) { - HashMap zplace = new HashMap(); - zplace.put(1, 100); - zplace.put(2, 0); - zplace.put(3, -100); - zplace.put(4, -200); - zplace.put(5, -300); - meshViews3[i].setTranslateX(nodes.get(nodes.size() - 1).getxCoordinate() / 5 - 307); - meshViews3[i].setTranslateY(nodes.get(nodes.size() - 1).getyCoordinate() / 5 - 70); - meshViews3[i].setTranslateZ(zplace.get(nodes.get(nodes.size() - 1).getFloor()) + 45); - meshViews3[i].setScaleX(MODEL_SCALE_FACTOR22); - meshViews3[i].setScaleY(MODEL_SCALE_FACTOR22); - meshViews3[i].setScaleZ(MODEL_SCALE_FACTOR22); - - PhongMaterial sample = new PhongMaterial(); - Image image2 = new Image(("images/ThreeDim/starticonreplace.jpg")); - sample.setDiffuseMap(image2); - //sample.setSpecularColor(Color.BEIGE); - //sample.setSpecularPower(16); - meshViews3[i].setMaterial(sample); - - meshViews3[i].getTransforms().setAll(new Rotate(0, Rotate.X_AXIS), new Rotate(90, Rotate.X_AXIS)); - } + boolean showComfort = false; + if(goal != null) { + if(goal.equals("6 South Patient Beds")) { + showComfort = true; + }} - SequentialTransition st = new SequentialTransition(); - for (int i = 0; i < nodes.size() - 1; i++) { - HashMap zplace = new HashMap(); - zplace.put(1, 100); - zplace.put(2, 0); - zplace.put(3, -100); - zplace.put(4, -200); - zplace.put(5, -300); - NodeData startNode = nodes.get(i); - NodeData endNode = nodes.get(i + 1); - int floor1 = startNode.getFloor(); - int floor2 = endNode.getFloor(); - boolean sameFloor = (floor1 == floor2); - - for (int j = 0; j < meshViews.length; j++) { - length = Math.sqrt(Math.pow(Math.abs(endNode.getxCoordinate() - startNode.getxCoordinate()), 2) + Math.pow(Math.abs((endNode.getyCoordinate() - startNode.getyCoordinate())), 2)); - TranslateTransition tt = new TranslateTransition(Duration.seconds(getPathTime(length)), meshViews[j]); //can change mph - tt.setInterpolator(Interpolator.LINEAR); - if (!sameFloor) { - length = Math.abs(endNode.getFloor() - startNode.getFloor()) * 100.0; - tt.setDuration(Duration.millis(1000)); - } - tt.setFromZ(zplace.get(startNode.getFloor()) - 27); - tt.setFromX(startNode.getxCoordinate() / 5 - 247); - tt.setFromY(startNode.getyCoordinate() / 5 - 148 - 47 + 42); - tt.setToZ(zplace.get(endNode.getFloor()) - 27); - tt.setToX(endNode.getxCoordinate() / 5 - 247); - tt.setToY(endNode.getyCoordinate() / 5 - 148 - 47 + 42); - tt.setCycleCount(1); - st.getChildren().add(tt); - //tt.setAutoReverse(true); -// if (i + 1 < anglez.size()) { -// RotateTransition rt = new RotateTransition(); -// rt.setDuration(Duration.seconds(getPathTime(length))); -// rt.setNode(meshViews[j]); -// rt.setAxis(Rotate.Z_AXIS); -// rt.setCycleCount(1); -// rt.setFromAngle(anglez.get(i)); -// rt.setToAngle(-anglez.get(i)); -// rt.getNode().getTransforms().setAll(new Rotate((-anglez.get(i + 1)+25), Rotate.Z_AXIS), new Rotate(180, Rotate.Y_AXIS)); -// -// st.getChildren().add(rt); -// } + RotateGroup group = new RotateGroup(); - } + for(int i = 1; i <= totalFloors; i++) { + boolean trans = !(begin.getFloor() == i || end.getFloor() == i); + Image floor = new Image("images/ThreeDim/floor" + i + ".png"); + Image transFloor = new Image("images/ThreeDim/transFloor" + i + ".png"); + int z = zplace.get(i); + group.getChildren().add(createFloor(floor, transFloor, z, trans)); } - st.setCycleCount(Timeline.INDEFINITE); - // st.setAutoReverse(true); - st.play(); - String thing4 = getClass().getResource("/images/ThreeDim/Clarinet.stl").toURI().getPath(); - MeshView[] clari = loadMeshViews(thing4); - double MODEL_SCALE_FACTOR7 = 0.7; - for (int i = 0; i < clari.length; i++) { -// meshViews[i].setTranslateX(0); -// meshViews[i].setTranslateY(0); -// meshViews[i].setTranslateZ(0); - clari[i].setScaleX(MODEL_SCALE_FACTOR7); - clari[i].setScaleY(MODEL_SCALE_FACTOR7); - clari[i].setScaleZ(MODEL_SCALE_FACTOR7); - - PhongMaterial sample = new PhongMaterial(); - Image image2 = new Image(("images/ThreeDim/geometric.jpg")); - sample.setDiffuseMap(image2); - //sample.setSpecularColor(Color.BEIGE); - //sample.setSpecularPower(16); - clari[i].setMaterial(sample); - - clari[i].getTransforms().setAll(new Rotate(0, Rotate.Z_AXIS), new Rotate(180, Rotate.X_AXIS)); - } - SequentialTransition st2 = new SequentialTransition(); - for (int i = 0; i < nodes.size() - 1; i++) { - HashMap zplace = new HashMap(); - zplace.put(1, 100); - zplace.put(2, 0); - zplace.put(3, -100); - zplace.put(4, -200); - zplace.put(5, -300); - NodeData startNode = nodes.get(i); - NodeData endNode = nodes.get(i + 1); - int floor1 = startNode.getFloor(); - int floor2 = endNode.getFloor(); - boolean sameFloor = (floor1 == floor2); - - for (int j = 0; j < clari.length; j++) { - length = Math.sqrt(Math.pow(Math.abs(endNode.getxCoordinate() - startNode.getxCoordinate()), 2) + Math.pow(Math.abs(endNode.getyCoordinate() - startNode.getyCoordinate()), 2)); - TranslateTransition tt = new TranslateTransition(Duration.seconds(getPathTime(length)), clari[j]); //can change mph - if (!sameFloor) { - length = Math.abs(endNode.getFloor() - startNode.getFloor()) * 100.0; - tt.setDuration(Duration.seconds(getPathTime(length))); - } - tt.setFromZ(zplace.get(startNode.getFloor()) - 80); - tt.setFromX(startNode.getxCoordinate() / 5 - 247); - tt.setFromY(startNode.getyCoordinate() / 5 - 148 - 47 + 110); - tt.setToZ(zplace.get(endNode.getFloor()) - 80); - tt.setToX(endNode.getxCoordinate() / 5 - 247); - tt.setToY(endNode.getyCoordinate() / 5 - 148 - 47 + 110); - tt.setInterpolator(Interpolator.LINEAR); - tt.setCycleCount(1); - //tt.setAutoReverse(true); - st2.getChildren().add(tt); - } - } - st2.setCycleCount(Timeline.INDEFINITE); - st2.play(); - // st.setAutoReverse(true); - - - String thing5 = getClass().getResource("/images/ThreeDim/hat.stl").toURI().getPath(); - - MeshView[] hati = loadMeshViews(thing5); - double MODEL_SCALE_FACTOR8 = 0.2; - for (int i = 0; i < hati.length; i++) { -// meshViews[i].setTranslateX(0); -// meshViews[i].setTranslateY(0); -// meshViews[i].setTranslateZ(0); - hati[i].setScaleX(MODEL_SCALE_FACTOR8); - hati[i].setScaleY(MODEL_SCALE_FACTOR8); - hati[i].setScaleZ(MODEL_SCALE_FACTOR8); - - PhongMaterial sample = new PhongMaterial(); - Image image2 = new Image(("images/ThreeDim/geometric.jpg")); - sample.setDiffuseMap(image2); - //sample.setSpecularColor(Color.BEIGE); - //sample.setSpecularPower(16); - hati[i].setMaterial(sample); - - hati[i].getTransforms().setAll(new Rotate(0, Rotate.Z_AXIS), new Rotate(90, Rotate.X_AXIS)); - } + Camera camera = new PerspectiveCamera(); + camera.setFarClip(10000); + camera.setTranslateY(-50); - SequentialTransition st3 = new SequentialTransition(); - for (int i = 0; i < nodes.size() - 1; i++) { - HashMap zplace = new HashMap(); - zplace.put(1, 100); - zplace.put(2, 0); - zplace.put(3, -100); - zplace.put(4, -200); - zplace.put(5, -300); + ImageView destinationCircle = new ImageView(new Image("/images/ThreeDim/pulse.gif")); + double destScale = 0.1; + destinationCircle.setScaleX(destScale); + destinationCircle.setScaleY(destScale); + destinationCircle.setScaleZ(destScale); + destinationCircle.setTranslateX(end.getxCoordinate() / 5 - 247 - 250); + destinationCircle.setTranslateZ(zplace.get(end.getFloor()) - 3); + destinationCircle.setTranslateY(end.getyCoordinate() / 5 - 148 - 250); + + ImageView pinny = new ImageView(new Image("images/Icons/end_pin.png")); + double MODEL_SCALE_FACTOR22 = 0.05; + pinny.setScaleX(MODEL_SCALE_FACTOR22); + pinny.setScaleY(MODEL_SCALE_FACTOR22); + pinny.setScaleZ(MODEL_SCALE_FACTOR22); + RotateGroup pinThing = new RotateGroup(); + pinThing.getChildren().add(pinny); + pinThing.getTransforms().add(new Rotate(90, Rotate.X_AXIS)); + pinThing.setTranslateZ(zplace.get(end.getFloor()) - 200 - 80); + pinThing.setTranslateX(end.getxCoordinate() / 5 - 307 - 250 + 150); + pinThing.setTranslateY(end.getyCoordinate() / 5 - 150); + + + URL docPath = getClass().getResource("/images/ThreeDim/childrens_toy.obj").toURI().toURL(); + MeshView[] doctor = loadModel(docPath); + for (int k = 0; k < doctor.length; k++) { + double MODEL_SCALE_FACTOR = 0.15; + doctor[k].setScaleX(MODEL_SCALE_FACTOR); + doctor[k].setScaleY(MODEL_SCALE_FACTOR); + doctor[k].setScaleZ(MODEL_SCALE_FACTOR); + + doctor[k].setTranslateZ(zplace.get(begin.getFloor())); + + doctor[k].getTransforms().setAll(new Rotate(-90, Rotate.Z_AXIS), new Rotate(90, Rotate.X_AXIS)); + } + RotateGroup docGroup = new RotateGroup(); + docGroup.getChildren().addAll(doctor); + group.getChildren().addAll(docGroup); + + URL nursePath = getClass().getResource("/images/ThreeDim/nurse.obj").toURI().toURL(); + MeshView[] nurse = loadModel(nursePath); + for (int k = 0; k < nurse.length; k++) { + double MODEL_SCALE_FACTOR = 1; + nurse[k].setScaleX(MODEL_SCALE_FACTOR); + nurse[k].setScaleY(MODEL_SCALE_FACTOR); + nurse[k].setScaleZ(MODEL_SCALE_FACTOR); + + nurse[k].setTranslateZ(zplace.get(6)); + nurse[k].setTranslateX(140); + nurse[k].setTranslateY(80); + + nurse[k].getTransforms().setAll(new Rotate(-90, Rotate.Z_AXIS), new Rotate(180, Rotate.X_AXIS)); + } + RotateGroup nurseGroup = new RotateGroup(); + nurseGroup.getChildren().addAll(nurse); + if(showComfort) + group.getChildren().addAll(nurseGroup); + + URL pikaPath = getClass().getResource("/images/ThreeDim/fry5poc2kyap.obj").toURI().toURL(); //jar will brake + MeshView[] pika = loadModel(pikaPath); + for (int k = 0; k < nurse.length; k++) { + double MODEL_SCALE_FACTOR = 1; + pika[k].setScaleX(MODEL_SCALE_FACTOR); + pika[k].setScaleY(MODEL_SCALE_FACTOR); + pika[k].setScaleZ(MODEL_SCALE_FACTOR); + } + RotateGroup pikaGroup = new RotateGroup(); + pikaGroup.getChildren().addAll(pika); + pikaGroup.setTranslateZ(zplace.get(6)); + pikaGroup.setTranslateX(180); + pikaGroup.setTranslateY(90); + pikaGroup.getTransforms().setAll(new Rotate(90, Rotate.Z_AXIS), new Rotate(90, Rotate.X_AXIS)); + if(showComfort) + group.getChildren().addAll(pikaGroup); + + URL dogPath = getClass().getResource("/images/ThreeDim/12228_Dog_v1_L2.obj").toURI().toURL(); + MeshView[] dog = loadModel(dogPath); + for (int k = 0; k < dog.length; k++) { + double MODEL_SCALE_FACTOR = 0.5; + dog[k].setScaleX(MODEL_SCALE_FACTOR); + dog[k].setScaleY(MODEL_SCALE_FACTOR); + dog[k].setScaleZ(MODEL_SCALE_FACTOR); + + dog[k].setTranslateZ(zplace.get(6)); + dog[k].setTranslateX(140); + dog[k].setTranslateY(110); + + dog[k].getTransforms().setAll(new Rotate(-90, Rotate.Z_AXIS), new Rotate(0, Rotate.X_AXIS)); + } + RotateGroup dogGroup = new RotateGroup(); + nurseGroup.getChildren().addAll(dog); + if(showComfort) + group.getChildren().addAll(dogGroup); + + URL patientPath = getClass().getResource("/images/ThreeDim/childrens_toy.obj").toURI().toURL(); + MeshView[] patient = loadModel(patientPath); + for (int k = 0; k < dog.length; k++) { + double MODEL_SCALE_FACTOR = 0.1; + patient[k].setScaleX(MODEL_SCALE_FACTOR); + patient[k].setScaleY(MODEL_SCALE_FACTOR); + patient[k].setScaleZ(MODEL_SCALE_FACTOR); + + patient[k].setTranslateZ(zplace.get(6) - 20); + patient[k].setTranslateX(150); + patient[k].setTranslateY(242); + } + RotateGroup patientGroup = new RotateGroup(); + nurseGroup.getChildren().addAll(patient); + if(showComfort) + group.getChildren().addAll(patientGroup); + + + URL bedPath = getClass().getResource("/images/ThreeDim/hospital_bed.obj").toURI().toURL(); //jar will brake + MeshView[] bed = loadModel(bedPath); + for (int k = 0; k < bed.length; k++) { + double MODEL_SCALE_FACTOR = 1; + bed[k].setScaleX(MODEL_SCALE_FACTOR); + bed[k].setScaleY(MODEL_SCALE_FACTOR); + bed[k].setScaleZ(MODEL_SCALE_FACTOR); + + bed[k].setTranslateX(160); + bed[k].setTranslateY(90); + bed[k].setTranslateZ(zplace.get(6)); + + bed[k].getTransforms().setAll(new Rotate(-90, Rotate.Z_AXIS), new Rotate(90, Rotate.X_AXIS)); + } + RotateGroup bedGroup = new RotateGroup(); + bedGroup.getChildren().addAll(bed); + if(showComfort) + group.getChildren().addAll(bedGroup); + + RotateGroup numberGroup = new RotateGroup(); + for(int i = 1; i <= totalFloors; i++) { + boolean selected = (begin.getFloor() == i || end.getFloor() == i); + Image number = new Image("images/ThreeDim/" + i + ".png"); + Image brightNumber = new Image("images/ThreeDim/" + i + "H.png"); + int z = zplace.get(i); + numberGroup.getChildren().add(floorNumbers(number, brightNumber, z, selected)); + } + + List elevatorGroup = new ArrayList<>(); + List invalidELEV = new ArrayList<>(); + int elevCount = 0; + + for(int i = 0; i < nodes.size() - 1; i++) { NodeData startNode = nodes.get(i); NodeData endNode = nodes.get(i + 1); - int floor1 = startNode.getFloor(); - int floor2 = endNode.getFloor(); - boolean sameFloor = (floor1 == floor2); - - for (int j = 0; j < clari.length; j++) { - length = Math.sqrt(Math.pow(Math.abs(endNode.getxCoordinate() - startNode.getxCoordinate()), 2) + Math.pow(Math.abs(endNode.getyCoordinate() - startNode.getyCoordinate()), 2)); - TranslateTransition tt = new TranslateTransition(Duration.seconds(getPathTime(length)), hati[j]); //can change mph - if (!sameFloor) { - length = Math.abs(endNode.getFloor() - startNode.getFloor()) * 100.0; - tt.setDuration(Duration.seconds(getPathTime(length))); - } - tt.setFromZ(zplace.get(startNode.getFloor()) - 80); - tt.setFromX(startNode.getxCoordinate() / 5 - 247); - tt.setFromY(startNode.getyCoordinate() / 5 - 148 - 47 + 150); - tt.setToZ(zplace.get(endNode.getFloor()) - 80); - tt.setToX(endNode.getxCoordinate() / 5 - 247); - tt.setInterpolator(Interpolator.LINEAR); - tt.setToY(endNode.getyCoordinate() / 5 - 148 - 47 + 150); - tt.setCycleCount(1); - //tt.setAutoReverse(true); - st3.getChildren().add(tt); - } - } - - - st3.setCycleCount(Timeline.INDEFINITE); - // st.setAutoReverse(true); - st3.play(); - - Group root = new Group(meshViews); - Group root10 = new Group(meshViews2); - Group root6 = new Group(meshViews3); - Group root9 = new Group(clari); - Group root80 = new Group(hati); - group.getChildren().add(root); - //group.getChildren().add(root10); - group.getChildren().add(root6); - //group.getChildren().add(root9); - //group.getChildren().add(root80); - - -// Path animated_path = new Path(); -// animated_path.getElements().add(new MoveTo(nodes.get(0).getxCoordinate() / 5 - 247, nodes.get(0).getyCoordinate() / 5 - 148)); -// for (NodeData node_itrat : nodes) { -// animated_path.getElements().add(new LineTo(node_itrat.getxCoordinate() / 5 - 247, node_itrat.getyCoordinate() / 5 - 148)); -// } -// PathTransition pathTransition = new PathTransition(); -// pathTransition.setDuration(Duration.seconds(0.5)); -// pathTransition.setPath(animated_path); -// pathTransition.setNode(sphere); - // pathTransition.setInterpolator(Interpolator.LINEAR); -// pathTransition.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT); -// pathTransition.setCycleCount(Timeline.INDEFINITE); -////pathTransition.setAutoReverse(true); -// pathTransition.play(); - - if (nodes.get(0).getFloor() == 1 || nodes.get(nodes.size() - 1).getFloor() == 1) { - - group.getChildren().add(getJuan(new Image(("images/ThreeDim/oney.png")), 0)); - } else { - group.getChildren().add(getJuan(new Image(("images/ThreeDim/juan (1).png")), 0)); - } - if (nodes.get(0).getFloor() == 2 || nodes.get(nodes.size() - 1).getFloor() == 2) { - group.getChildren().add(getJuan(new Image(("images/ThreeDim/twoy.png")), -100)); - } else { - group.getChildren().add(getJuan(new Image(("images/ThreeDim/juan (5).png")), -100)); - } - if (nodes.get(0).getFloor() == 3 || nodes.get(nodes.size() - 1).getFloor() == 3) { - - group.getChildren().add(getJuan(new Image(("images/ThreeDim/threey.png")), -200)); - } else { - group.getChildren().add(getJuan(new Image(("images/ThreeDim/juan (4).png")), -200)); - } - if (nodes.get(0).getFloor() == 4 || nodes.get(nodes.size() - 1).getFloor() == 4) { - group.getChildren().add(getJuan(new Image(("images/ThreeDim/foury.png")), -300)); - } else { - group.getChildren().add(getJuan(new Image(("images/ThreeDim/juan (3).png")), -300)); - } - if (nodes.get(0).getFloor() == 5 || nodes.get(nodes.size() - 1).getFloor() == 5) { - - group.getChildren().add(getJuan(new Image(("images/ThreeDim/fivey.png")), -400)); - } else { - group.getChildren().add(getJuan(new Image(("images/ThreeDim/juan (2).png")), -400)); - } - - //group.getChildren().add(wongBox); - - Group buttonsGroup = new Group(); - Button aych = new Button(); - aych.setTranslateY(200); - aych.setText("down"); - aych.setOnAction(e -> { - KeyEvent press = new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.H, false, false, false, false); - primaryStage.fireEvent(press); - }); - Button ghee = new Button(); - ghee.setTranslateY(100); - ghee.setText("up"); - ghee.setOnAction(e -> { - KeyEvent press = new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.G, false, false, false, false); - primaryStage.fireEvent(press); - }); - Button thee = new Button(); - thee.setText("left"); - thee.setTranslateY(300); - thee.setOnAction(e -> { - KeyEvent press = new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.T, false, false, false, false); - primaryStage.fireEvent(press); - }); - Button why = new Button(); - why.setText("right"); - why.setTranslateY(400); - - why.setOnAction(e -> { - KeyEvent press = new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.Y, false, false, false, false); - primaryStage.fireEvent(press); - }); - - - /* for(NodeData data : nodes) { - if(data.getFloor() == 2 || data.getFloor() == 3) { - Sphere sphere = new Sphere(5); - sphere.setTranslateX(data.getxCoordinate() / 5 - 247); - sphere.setTranslateY(data.getyCoordinate() / 5 - 148); - if(data.getFloor() == 3) { - sphere.setTranslateZ(-100); + for(int j = 1; j <= totalFloors; j++) { + if(startNode.getFloor() == j) { + int radius = 2; + if(startNode.getNodeType().equals("ELEV")) { + URL elevPath = getClass().getResource("/images/ThreeDim/boneless.obj").toURI().toURL(); //jar will brake + MeshView[] elevator = loadModel(elevPath); + for (int k = 0; k < elevator.length; k++) { + double MODEL_SCALE_FACTOR = 30; + elevator[k].setScaleX(MODEL_SCALE_FACTOR); + elevator[k].setScaleY(MODEL_SCALE_FACTOR); + elevator[k].setScaleZ(MODEL_SCALE_FACTOR); + + elevator[k].setTranslateX(startNode.getxCoordinate() / 5 - 244 - 45); + elevator[k].setTranslateY(startNode.getyCoordinate() / 5 - 148 - 9); + elevator[k].setTranslateZ(zplace.get(startNode.getFloor()) - 60); + + elevator[k].getTransforms().setAll(new Rotate(-90, Rotate.Z_AXIS), new Rotate(90, Rotate.X_AXIS)); + invalidELEV.add(i+1); + } + if(!invalidELEV.contains(i)) { + elevatorGroup.add(new Group(elevator)); + } + } + else { + Point3D startPoint = new Point3D(startNode.getxCoordinate() / 5 - 247, startNode.getyCoordinate() / 5 - 148, zplace.get(startNode.getFloor())); + Point3D endPoint = new Point3D(endNode.getxCoordinate() / 5 - 247, endNode.getyCoordinate() / 5 - 148, zplace.get(endNode.getFloor())); + group.getChildren().addAll(drawCylinder(startPoint, endPoint, radius)); + } } - PhongMaterial material = new PhongMaterial(); - Image image = new Image(("images/geometric.jpg")); - material.setDiffuseMap(image); - sphere.setMaterial(material); - group.getChildren().add(sphere); } } - Set ed = dbc.getAllEdges();*/ + RotateGroup personGroup = new RotateGroup(); + group.getChildren().add(numberGroup); + group.getChildren().addAll(elevatorGroup); + group.getChildren().add(destinationCircle); + group.getChildren().add(new AmbientLight(Color.WHITE)); - /*for(EdgeData data : ed) { - if(dbc.getNode(data.getStartNode()).getFloor() == 2 || dbc.getNode(data.getStartNode()).getFloor() == 3) { - NodeData startNode = dbc.getNode(data.getStartNode()); - NodeData endNode = dbc.getNode(data.getEndNode()); - if(dbc.getNode(data.getStartNode()).getFloor() == 2) { - Point3D point3 = new Point3D(startNode.getxCoordinate() / 5 - 247, startNode.getyCoordinate() / 5 - 148, 0); - Point3D point4 = new Point3D(endNode.getxCoordinate() / 5 - 247, endNode.getyCoordinate() / 5 - 148, 0); - group.getChildren().add(createConnection(point3, point4, 2)); + SequentialTransition st = new SequentialTransition(); + ArrayList floorPath = new ArrayList<>(); + for(int i = 0; i < nodes.size() - 1; i++) { + NodeData n1 = nodes.get(i); + NodeData n2 = nodes.get(i+1); + boolean elev = !(n1.getFloor() == n2.getFloor()); + if(elev) { + st.getChildren().add(getFloorPath(docGroup, floorPath)); + floorPath.clear(); + double offsetX = 0; + double offsetY = 0; + if(n1.getNodeID().substring(7,8).equals("X")) { + offsetX = 0; + offsetY = 150; } - if(dbc.getNode(data.getStartNode()).getFloor() == 3) { - Point3D point3 = new Point3D(startNode.getxCoordinate() / 5 - 247, startNode.getyCoordinate() / 5 - 148, -100); - Point3D point4 = new Point3D(endNode.getxCoordinate() / 5 - 247, endNode.getyCoordinate() / 5 - 148, -100); - group.getChildren().add(createConnection(point3, point4, 2)); + else if(n1.getNodeID().substring(7,8).equals("Z")) { + offsetX = -35; + offsetY = 5; } - } - }*/ - Group root2 = new Group(); - root2.getChildren().add(group); - // root2.getChildren().add(slider); - root2.getChildren().add(prepareImageView()); - - - SequentialTransition str = new SequentialTransition(); - Ellipse ellipseEarth = new Ellipse(); - ellipseEarth.setRadiusX(100); - ellipseEarth.setCenterY(100); - group.getChildren().add(ellipseEarth); - - group.getChildren().add(s); - + TranslateTransition tt = new TranslateTransition(Duration.seconds(Math.abs(n1.getFloor() - n2.getFloor())), docGroup); + tt.setFromZ((zplace.get(n1.getFloor())) - ((2-begin.getFloor()) * floorDist)); + tt.setFromX(n1.getxCoordinate() / 5 - 247 - 20); + tt.setFromY(n1.getyCoordinate() / 5 - 24); + tt.setToZ(zplace.get(n2.getFloor()) - ((2-begin.getFloor()) * floorDist)); + tt.setToX(n1.getxCoordinate() / 5 - 247 - 20); + tt.setToY(n1.getyCoordinate() / 5 - 24); + tt.setCycleCount(1); - for (int i = 0; i < nodes.size() - 1; i++) { - HashMap zplace = new HashMap(); - zplace.put(1, 100); - zplace.put(2, 0); - zplace.put(3, -100); - zplace.put(4, -200); - zplace.put(5, -300); - NodeData startNode = nodes.get(i); - NodeData endNode = nodes.get(i + 1); - if (startNode.getFloor() == 2) { - Point3D point3 = new Point3D(startNode.getxCoordinate() / 5 - 247, startNode.getyCoordinate() / 5 - 148, 0); - Point3D point4 = new Point3D(endNode.getxCoordinate() / 5 - 247, endNode.getyCoordinate() / 5 - 148, 0); - group.getChildren().add(createConnection(point3, point4, 2)); - // magical(startNode, endNode, str, s, group, point3, point4); - } - if (startNode.getFloor() == 3) { - Point3D point3 = new Point3D(startNode.getxCoordinate() / 5 - 247, startNode.getyCoordinate() / 5 - 148, -100); - Point3D point4 = new Point3D(endNode.getxCoordinate() / 5 - 247, endNode.getyCoordinate() / 5 - 148, -100); - group.getChildren().add(createConnection(point3, point4, 2)); - // magical(startNode, endNode, str, s, group, point3, point4); - } - if (startNode.getFloor() == 1) { - Point3D point3 = new Point3D(startNode.getxCoordinate() / 5 - 247, startNode.getyCoordinate() / 5 - 148, +100); - Point3D point4 = new Point3D(endNode.getxCoordinate() / 5 - 247, endNode.getyCoordinate() / 5 - 148, +100); - group.getChildren().add(createConnection(point3, point4, 2)); - // magical(startNode, endNode, str, s, group, point3, point4); - } - if (startNode.getFloor() == 4) { - Point3D point3 = new Point3D(startNode.getxCoordinate() / 5 - 247, startNode.getyCoordinate() / 5 - 148, -200); - Point3D point4 = new Point3D(endNode.getxCoordinate() / 5 - 247, endNode.getyCoordinate() / 5 - 148, -200); - group.getChildren().add(createConnection(point3, point4, 2)); - //magical(startNode, endNode, str, s, group, point3, point4); + TranslateTransition ttELEV = new TranslateTransition(Duration.seconds(Math.abs(n1.getFloor() - n2.getFloor())), elevatorGroup.get(elevCount)); + ttELEV.setFromZ(zplace.get(n1.getFloor()) - ((2-n1.getFloor()) * floorDist)); + ttELEV.setFromX(n1.getxCoordinate() / 5 - 244 + offsetX); + ttELEV.setFromY(n1.getyCoordinate() / 5 - 240 + offsetY); + ttELEV.setToZ(zplace.get(n2.getFloor()) - ((2-n1.getFloor()) * floorDist)); + ttELEV.setToX(n1.getxCoordinate() / 5 - 244 + offsetX); + ttELEV.setToY(n1.getyCoordinate() / 5 - 240 + offsetY); + ttELEV.setCycleCount(1); + + ParallelTransition pllt = new ParallelTransition(tt, ttELEV); + st.getChildren().addAll(pllt); + elevCount++; } - if (startNode.getFloor() == 5) { - Point3D point3 = new Point3D(startNode.getxCoordinate() / 5 - 247, startNode.getyCoordinate() / 5 - 148, -300); - Point3D point4 = new Point3D(endNode.getxCoordinate() / 5 - 247, endNode.getyCoordinate() / 5 - 148, -300); - group.getChildren().add(createConnection(point3, point4, 2)); - // magical(startNode, endNode, str, s, group, point3, point4); + else { + floorPath.add(n1); floorPath.add(n2); } - if (startNode.getNodeType().equals("ELEV")) { - int floor1 = startNode.getFloor(); - int floor2 = endNode.getFloor(); - //String xyz = spec1.getNodeID().substring(7,8); - Point3D elev1 = new Point3D(startNode.getxCoordinate() / 5 - 247, startNode.getyCoordinate() / 5 - 148, zplace.get(floor1)); - Point3D elev2 = new Point3D(endNode.getxCoordinate() / 5 - 247, endNode.getyCoordinate() / 5 - 148, zplace.get(floor2)); - group.getChildren().add(createConnection(elev1, elev2, 5)); + if(i == nodes.size() - 2) { + st.getChildren().add(getFloorPath(docGroup, floorPath)); } - /* if(startNode.getNodeID().equals("SELEV00X02")) { - NodeData elevr1 = dbc.getNode("SELEV00X02"); - NodeData elevr2 = dbc.getNode("SELEV00X03"); - Point3D elev1 = new Point3D(elevr1.getxCoordinate() / 5 - 247, elevr1.getyCoordinate() / 5 - 148, 0); - Point3D elev2 = new Point3D(elevr2.getxCoordinate() / 5 - 247, elevr2.getyCoordinate() / 5 - 148, -100); - group.getChildren().add(createConnection(elev1, elev2, 5)); - } - if(startNode.getNodeID().equals("SELEV00Y02")) { - NodeData elevr1 = dbc.getNode("SELEV00Y02"); - NodeData elevr2 = dbc.getNode("SELEV00Y03"); - Point3D elev1 = new Point3D(elevr1.getxCoordinate() / 5 - 247, elevr1.getyCoordinate() / 5 - 148, 0); - Point3D elev2 = new Point3D(elevr2.getxCoordinate() / 5 - 247, elevr2.getyCoordinate() / 5 - 148, -100); - group.getChildren().add(createConnection(elev1, elev2, 5)); - } - if(startNode.getNodeID().equals("SELEV00Z02")) { - NodeData elevr1 = dbc.getNode("SELEV00Z02"); - NodeData elevr2 = dbc.getNode("SELEV00Z03"); - Point3D elev1 = new Point3D(elevr1.getxCoordinate() / 5 - 247, elevr1.getyCoordinate() / 5 - 148, 0); - Point3D elev2 = new Point3D(elevr2.getxCoordinate() / 5 - 247, elevr2.getyCoordinate() / 5 - 148, -100); - group.getChildren().add(createConnection(elev1, elev2, 5)); - }*/ } + st.setCycleCount(Timeline.INDEFINITE); + st.play(); + group.getChildren().add(pinThing); + Group elevIcons = getElevIcons(); + group.getChildren().add(elevIcons); + + Group foodIcons = getFoodIcons(); + group.getChildren().add(foodIcons); + + Group retlIcons = getRETLIcons(); + group.getChildren().add(retlIcons); + + Group stairIcons = getSTAIcons(); + group.getChildren().add(stairIcons); + + Group restIcons = getRESTIcons(); + group.getChildren().add(restIcons); + + group.rotateByX(-63); + group.translateXProperty().set((WIDTH - 192 - 49)/2 - 24); + group.translateYProperty().set(632/2); + group.translateZProperty().set(zplace.get(begin.getFloor()) - 700); + group.translateZProperty().set(group.getTranslateZ() + 100); + + Group root = new Group(); + ImageView imageView = getOverlay(); + root.getChildren().add(imageView); + + Label dest = new Label(); + if(goal != null) { + dest.setText(goal);} + dest.setScaleX(3); + dest.setScaleY(3); + dest.setScaleZ(3); + dest.relocate(568, 18); + dest.setTextFill(Color.web("#ffffff")); + + root.getChildren().add(dest); + + Button elevatorButton = new Button(); + elevatorButton.relocate(97,57); + elevatorButton.setPrefSize(180,50); + elevatorButton.setStyle("-fx-background-color: TRANSPARENT"); + elevatorButton.setOnAction(e -> onElevClicked(elevIcons)); + root.getChildren().add(elevatorButton); + + Button foodButton = new Button(); + foodButton.relocate(340,56); + foodButton.setPrefSize(140,50); + foodButton.setStyle("-fx-background-color: TRANSPARENT"); + root.getChildren().add(foodButton); + foodButton.setOnAction(e -> onFoodClicked(foodIcons)); + + Button bathroomButton = new Button(); + bathroomButton.relocate(538,56); + bathroomButton.setPrefSize(206,50); + bathroomButton.setStyle("-fx-background-color: TRANSPARENT"); + root.getChildren().add(bathroomButton); + bathroomButton.setOnAction(e -> onRestClicked(restIcons)); + + + Button retailButton = new Button(); + retailButton.relocate(770,56); + retailButton.setPrefSize(150,50); + retailButton.setStyle("-fx-background-color: TRANSPARENT"); + root.getChildren().add(retailButton); + retailButton.setOnAction(e -> onRetailClicked(retlIcons)); + + + Button stairsButton = new Button(); + stairsButton.relocate(982,56); + stairsButton.setPrefSize(160,50); + stairsButton.setStyle("-fx-background-color: TRANSPARENT"); + root.getChildren().add(stairsButton); + stairsButton.setOnAction(e -> onStairsClicked(stairIcons)); + + camera.setTranslateZ(zplace.get(begin.getFloor()) - 20); + dest.setTranslateZ(dest.getTranslateZ() + zplace.get(begin.getFloor())); + + AnchorPane globalRoot = new AnchorPane(); + imageView.setScaleX(imageView.getScaleX() - 0.01); + imageView.setScaleY(imageView.getScaleY() - 0.01); + imageView.setScaleZ(imageView.getScaleZ() - 0.01); + imageView.setTranslateX(imageView.getTranslateX() + 1); + imageView.setTranslateY(imageView.getTranslateY() + 48); + globalRoot.getChildren().add(root); + Scene scene = new Scene(globalRoot, WIDTH - 192, HEIGHT, true); + globalRoot.setStyle("-fx-background-color: #8f8f8f"); + + SubScene sub = new SubScene + (group, WIDTH - 192 - 49, 632, true, SceneAntialiasing.BALANCED); + sub.setCamera(camera); + sub.setFill(Color.web("#8f8f8f")); + mouseControl(group, sub, primaryStage, numberGroup, elevatorButton, foodButton, bathroomButton, retailButton, stairsButton); + globalRoot.getChildren().add(sub); + sub.setTranslateX(sub.getTranslateX() + 25); + sub.setTranslateY(sub.getTranslateY() + 106); + + primaryStage.setTitle("MAP"); + + root.getChildren().get(0).toBack(); + + group.setTranslateZ(group.getTranslateZ() + 0.5*(-zplace.get(begin.getFloor()))); + + if(allFloorsInvolved.size() > 1) { + int max = Collections.max(allFloorsInvolved); + int min = Collections.min(allFloorsInvolved); + group.setTranslateY((group.getTranslateY() - (3-max) * floorDist) - (group.getTranslateY() - (3-min) * floorDist)); + group.setTranslateZ(group.getTranslateZ() + 125*(max-min)); + } + else { + group.setTranslateY(group.getTranslateY() - (3-begin.getFloor()) * floorDist); + } + + elevatorButton.fire(); + foodButton.fire(); + retailButton.fire(); + bathroomButton.fire(); + stairsButton.fire(); - str.setCycleCount(Timeline.INDEFINITE); - str.play(); - primaryStage.addEventHandler(KeyEvent.KEY_PRESSED, event -> { - switch (event.getCode()) { - case W: - group.translateZProperty().set(group.getTranslateZ() + 100); - break; - case S: - group.translateZProperty().set(group.getTranslateZ() - 100); - break; - case Q: - group.rotateByX(10); - break; - case E: - group.rotateByX(-10); - break; - case A: - group.rotateByY(10); - break; - case D: - group.rotateByY(-10); - break; - case T: - group.rotateByZ(-10); - break; - case Y: - group.rotateByZ(10); - break; - case G: - group.setTranslateY(group.getTranslateY() - 100); - break; - case H: - group.setTranslateY(group.getTranslateY() + 100); - break; - case UP: - group.setTranslateY(group.getTranslateY() - 100); - break; - case DOWN: - group.setTranslateY(group.getTranslateY() + 100); - break; - case LEFT: - group.rotateByZ(-10); - break; - case RIGHT: - group.rotateByZ(10); - break; - } - }); - - for (int i = 0; i < 7; i++) { - KeyEvent press = new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.E, false, false, false, false); - primaryStage.fireEvent(press); - } - for (int i = 0; i < 1; i++) { - KeyEvent press = new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.T, false, false, false, false); - primaryStage.fireEvent(press); - } - group.setTranslateY(group.getTranslateY() + 70); - group.translateXProperty().set(WIDTH / 2); - group.translateYProperty().set(HEIGHT / 2); - group.translateZProperty().set(zplace1.get(nodes.get(0).getFloor())); - Scene scene = new Scene(root2, WIDTH, HEIGHT, true); - group.translateZProperty().set(group.getTranslateZ() - 700); - camera.setFarClip(1000); - scene.setFill(Color.DIMGRAY); - scene.setCamera(camera); - initMouseControl(group, scene, primaryStage); - - primaryStage.setTitle("3D View"); primaryStage.setScene(scene); + primaryStage.resizableProperty().set(false); + primaryStage.sizeToScene(); primaryStage.show(); - } - static MeshView[] loadMeshViews(String filename) { - File file = new File(filename); - StlMeshImporter importer = new StlMeshImporter(); - importer.read(file); - Mesh mesh = importer.getImport(); - return new MeshView[]{new MeshView(mesh)}; + AnimationTimer timer = new AnimationTimer() { + private long lastUpdate = 0 ; + @Override + public void handle(long now) { + if (now - lastUpdate >= 300_000_000) { + onFloorMove(group, docGroup, numberGroup, begin); + lastUpdate = now ; + } + } + }; + timer.start(); } - private ImageView prepareImageView() { - Image image = new Image("images/ThreeDim/background.jpg"); - ImageView imageView = new ImageView(image); - imageView.setPreserveRatio(true); - double scale = 0.7; - imageView.setScaleX(scale); - imageView.setScaleY(scale); - imageView.setScaleZ(scale); - imageView.getTransforms().add(new Translate(-800, -1100, 0)); - return imageView; - } + private MeshView[] loadModel(URL url) { + ObjModelImporter importer = new ObjModelImporter(); + importer.read(url); - public double distance3D(Point3D start, Point3D end) { - double result = Math.sqrt(Math.pow((end.getX() - start.getX()), 2) + Math.pow((end.getX() - start.getX()), 2) + Math.pow((end.getX() - start.getX()), 2)); - return result; + return importer.getImport(); } - public Cylinder createConnection(Point3D origin, Point3D target, int radius) { + public Cylinder drawCylinder(Point3D startPoint, Point3D endPoint, int radius) { Point3D yAxis = new Point3D(0, 1, 0); - Point3D diff = target.subtract(origin); + Point3D diff = endPoint.subtract(startPoint); double height = diff.magnitude(); - - Point3D mid = target.midpoint(origin); + Point3D mid = endPoint.midpoint(startPoint); Translate moveToMidpoint = new Translate(mid.getX(), mid.getY(), mid.getZ()); - Point3D axisOfRotation = diff.crossProduct(yAxis); double angle = Math.acos(diff.normalize().dotProduct(yAxis)); Rotate rotateAroundCenter = new Rotate(-Math.toDegrees(angle), axisOfRotation); - Cylinder line = new Cylinder(radius, height); - - if (radius >= 5) { - PhongMaterial material = new PhongMaterial(); - Image image = new Image(("images/ThreeDim/stairs.png")); - material.setDiffuseMap(image); - - line.setMaterial(material); - } + Cylinder cylinder = new Cylinder(radius, height); - if (radius < 5) { - PhongMaterial material = new PhongMaterial(); - Image image = new Image(("images/ThreeDim/geometric.jpg")); - material.setDiffuseMap(image); + Image texture = new Image(("images/ThreeDim/edgeTexture.jpg")); + if(radius >= 5) { texture = new Image(("images/ThreeDim/elevatorTexture.png")); } - line.setMaterial(material); - } + PhongMaterial material = new PhongMaterial(); + material.setDiffuseMap(texture); + cylinder.setMaterial(material); - line.getTransforms().addAll(moveToMidpoint, rotateAroundCenter); + cylinder.getTransforms().addAll(moveToMidpoint, rotateAroundCenter); - return line; + return cylinder; } - double calculateAngle(double P1X, double P1Y, double P2X, double P2Y, - double P3X, double P3Y) { - - double numerator = P2Y * (P1X - P3X) + P1Y * (P3X - P2X) + P3Y * (P2X - P1X); - double denominator = (P2X - P1X) * (P1X - P3X) + (P2Y - P1Y) * (P1Y - P3Y); - double ratio = numerator / denominator; + private Node createFloor(Image floor, Image transFloor, int z, boolean trans) { + PhongMaterial material = new PhongMaterial(); + Box floorPlane = new Box(495, 297, 0); - double angleRad = Math.atan(ratio); - double angleDeg = (angleRad * 180) / Math.PI; + if(!trans) {material.setDiffuseMap(floor);} + else {material.setDiffuseMap(transFloor);} - if (angleDeg < 0) { - angleDeg = 180 + angleDeg; - } + floorPlane.setTranslateZ(z); + floorPlane.setMaterial(material); - return angleDeg; + return floorPlane; } - private Node prepareSecondBox(int flip) { - PhongMaterial material = new PhongMaterial(); - Box box = new Box(495, 297, 0); - - if (flip == 0) { - Image image = new Image(("images/ThreeDim/greif3.png")); - material.setDiffuseMap(image); - box.setTranslateZ(-100); - box.setMaterial(material); - box.setOpacity(0.1); - } + class RotateGroup extends Group { + Rotate r; + Transform t = new Rotate(); - if (flip == 1) { - Image image = new Image(("images/ThreeDim/san.png")); - material.setDiffuseMap(image); - box.setTranslateZ(-100); - box.setMaterial(material); - box.setOpacity(0.1); + void rotateByX(int ang) { + r = new Rotate(ang, Rotate.X_AXIS); + t = t.createConcatenation(r); + this.getTransforms().clear(); + this.getTransforms().addAll(t); } - return box; - } - private Node prepareThirdBox(int flip) { - PhongMaterial material = new PhongMaterial(); - Box box = new Box(495, 297, 0); - - if (flip == 0) { - Image image = new Image(("images/ThreeDim/grief1.png")); - material.setDiffuseMap(image); - box.setTranslateZ(+100); - box.setMaterial(material); - box.setOpacity(0.1); + void rotateByY(int ang) { + r = new Rotate(ang, Rotate.Y_AXIS); + t = t.createConcatenation(r); + this.getTransforms().clear(); + this.getTransforms().addAll(t); } - if (flip == 1) { - Image image = new Image(("images/ThreeDim/yi.png")); - material.setDiffuseMap(image); - box.setTranslateZ(+100); - box.setMaterial(material); - box.setOpacity(0.1); + + void rotateByZ(int ang) { + r = new Rotate(ang, Rotate.Z_AXIS); + t = t.createConcatenation(r); + this.getTransforms().clear(); + this.getTransforms().addAll(t); } - return box; } - private Node prepareFourthBox(int flip) { + private Box floorNumbers(Image number, Image brightNumber, int z, boolean selected) { PhongMaterial material = new PhongMaterial(); - Box box = new Box(495, 297, 0); - - if (flip == 0) { - Image image = new Image(("images/ThreeDim/grief4.png")); - material.setDiffuseMap(image); - box.setTranslateZ(-200); - box.setMaterial(material); - box.setOpacity(0.1); - } - if (flip == 1) { - Image image = new Image(("images/ThreeDim/si.png")); - material.setDiffuseMap(image); - box.setTranslateZ(-200); - box.setMaterial(material); - box.setOpacity(0.1); - } - return box; + material.setDiffuseMap(number); + floorAddress.add(material.getDiffuseMap().toString()); + + Box floorNum = new Box(40, 0, 70); + floorNum.setTranslateZ(z); + floorNum.setTranslateX(250); + floorNum.setTranslateY(100); + floorNum.setMaterial(material); + + return floorNum; } - private Node prepareFifthBox(int flip) { - PhongMaterial material = new PhongMaterial(); - Box box = new Box(495, 297, 0); + private void mouseControl(RotateGroup group, SubScene scene, Stage stage, RotateGroup numberGroup, Button b1, Button b2, Button b3, Button b4, Button b5) { + stage.addEventFilter(MouseEvent.MOUSE_PRESSED, (final MouseEvent mouseEvent) -> { + oldX = mouseEvent.getX(); + oldY = mouseEvent.getY(); + if(oldY > 80 && oldY < 100) { + if(oldX > 97 && oldX < 275) b1.fire(); + if(oldX > 3441 && oldX < 475) b2.fire(); + if(oldX > 540 && oldX < 740) b3.fire(); + if(oldX > 770 && oldX < 916) b4.fire(); + if(oldX > 984 && oldX < 1140) b5.fire(); - if (flip == 0) { - Image image = new Image(("images/ThreeDim/grief5.png")); - material.setDiffuseMap(image); + } + }); - box.setTranslateZ(-300); - box.setMaterial(material); - box.setOpacity(0.1); - } - if (flip == 1) { - Image image = new Image(("images/ThreeDim/wu.png")); - material.setDiffuseMap(image); + stage.addEventFilter(MouseEvent.MOUSE_DRAGGED, (final MouseEvent event) -> { + if(event.isPrimaryButtonDown() && !event.isControlDown()) { + if(event.getSceneY() > oldY) { group.setTranslateY(group.getTranslateY() + 4); } + else {group.setTranslateY(group.getTranslateY() - 4);} + oldY = event.getSceneY(); + } + if(event.isPrimaryButtonDown() && event.isControlDown()) { + if(event.getSceneX() > oldX) { group.rotateByZ(-1); numberGroup.rotateByZ(1);} + else {group.rotateByZ(1); numberGroup.rotateByZ(-1);} + oldX = event.getSceneX(); + } + if(event.isSecondaryButtonDown()) { + group.setTranslateX(group.getTranslateX() + (event.getX() - oldX)); + oldX = event.getX(); + } + }); - box.setTranslateZ(-300); - box.setMaterial(material); - box.setOpacity(0.1); - } - return box; + stage.addEventHandler(ScrollEvent.SCROLL, event -> { + double delta = event.getDeltaY(); + if(group.getTranslateZ() < 324 && delta > 0) { + group.translateZProperty().set(group.getTranslateZ() + delta); + } + else if (group.getTranslateZ() > -938 && delta < 0) { + group.translateZProperty().set(group.getTranslateZ() + delta); + } + }); } - private Box prepareBox(int flip) { - PhongMaterial material = new PhongMaterial(); - Box box = new Box(495, 297, 0); + private PathTransition getFloorPath(RotateGroup personGroup, ArrayList currentFloorPath) { + Path personPath = new Path(); + personPath.getElements().add(new MoveTo(currentFloorPath.get(0).getxCoordinate() / 5 - 247, currentFloorPath.get(0).getyCoordinate() / 5 - 148)); + double length = 0; + double prevX = currentFloorPath.get(0).getxCoordinate(); + double prevY = currentFloorPath.get(0).getyCoordinate(); + + for (NodeData node : currentFloorPath) { + personPath.getElements().add(new LineTo(node.getxCoordinate() / 5 - 247, node.getyCoordinate() / 5 - 148)); + length += Math.sqrt(Math.pow((Math.abs(prevX - node.getxCoordinate())), 2) + Math.pow((Math.abs(prevY - node.getyCoordinate())),2)); + prevX = node.getxCoordinate(); + prevY = node.getyCoordinate(); + } + + PathTransition pt = new PathTransition(); + pt.setNode(personGroup); + pt.setDuration(Duration.seconds(length/200)); + pt.setPath(personPath); + pt.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT); + pt.setCycleCount(1); + return pt; + } - if (flip == 0) { - Image image = new Image(("images/ThreeDim/grief2.png")); - material.setDiffuseMap(image); - box.setMaterial(material); - box.setOpacity(0.1); - } + private RotateGroup getElevIcons() { - if (flip == 1) { - Image image = new Image(("images/ThreeDim/er.png")); - material.setDiffuseMap(image); - box.setMaterial(material); - box.setOpacity(0.1); + DatabaseController dbc = new DatabaseController(); + RotateGroup elevICON = new RotateGroup(); + Set nd = dbc.getAllNodesOfType("ELEV"); + for(NodeData data : nd) { + if(!nodes.contains(data) && allFloorsInvolved.contains(data.getFloor())) { + Image image = new Image("/images/ThreeDim/elevICON.png"); + ImageView imageView = new ImageView(image); + imageView.setPreserveRatio(true); + imageView.setTranslateX(data.getxCoordinate() / 5 - 500); + imageView.setTranslateY(data.getyCoordinate() / 5 - 390); + imageView.setTranslateZ(zplace.get(data.getFloor()) - 15); + double scale = 0.02; + imageView.setScaleX(scale); + imageView.setScaleY(scale); + imageView.setScaleZ(scale); + imageView.getTransforms().add(new Rotate(90, Rotate.X_AXIS)); + elevICON.getChildren().add(imageView); + } } - return box; + return elevICON; } - private void initMouseControl(SmartGroup group, Scene scene, Stage stage) { -// Rotate xRotate; -// Rotate yRotate; -// -// group.getTransforms().addAll( -// xRotate = new Rotate(0, Rotate.X_AXIS), -// yRotate = new Rotate(0, Rotate.Y_AXIS) -// ); -// xRotate.angleProperty().bind(angleX); -// yRotate.angleProperty().bind(angleY); -// -// scene.setOnMousePressed(event -> { -// anchorX = event.getSceneX(); -// anchorY = event.getSceneY(); -// anchorAngleX = angleX.get(); -// anchorAngleY = angleY.get(); -// }); -// -// scene.setOnMouseDragged(event -> { -// angleX.set(anchorAngleX - (anchorY - event.getSceneY())); -// angleY.set(anchorAngleY + anchorX - event.getSceneX()); -// }); + private RotateGroup getFoodIcons() { - stage.addEventHandler(ScrollEvent.SCROLL, event -> { - double delta = event.getDeltaY(); - group.translateZProperty().set(group.getTranslateZ() + delta); - }); + ArrayList validFood = new ArrayList<>(); + validFood.add("Atrium Cafe"); + validFood.add("Starbucks"); + validFood.add("Food Services"); + validFood.add("Outdoor Dining Terrace"); + RotateGroup foodICON = new RotateGroup(); + DatabaseController dbc = new DatabaseController(); + Set nd = dbc.getAllNodesOfType("RETL"); + for(NodeData data : nd) { + if(nodes.get(nodes.size()-1).getNodeID() != data.getNodeID() && allFloorsInvolved.contains(data.getFloor())) { + if (validFood.contains(data.getLongName())) { + Image image = new Image("/images/ThreeDim/foodICON.png"); + ImageView imageView = new ImageView(image); + imageView.setPreserveRatio(true); + imageView.setTranslateX(data.getxCoordinate() / 5 - 1070); + imageView.setTranslateY(data.getyCoordinate() / 5 - 910); + imageView.setTranslateZ(zplace.get(data.getFloor()) - 25); + double scale = 0.01; + imageView.setScaleX(scale); + imageView.setScaleY(scale); + imageView.setScaleZ(scale); + imageView.getTransforms().add(new Rotate(90, Rotate.X_AXIS)); + foodICON.getChildren().add(imageView); + } + } + } + return foodICON; } + private RotateGroup getRETLIcons() { - public static void main(String[] args) { - launch(args); + + ArrayList validRetail = new ArrayList<>(); + validRetail.add("Phatmacy"); + validRetail.add("Giftshop Hall"); + + RotateGroup retailICON = new RotateGroup(); + DatabaseController dbc = new DatabaseController(); + Set nd = dbc.getAllNodesOfType("RETL"); + for(NodeData data : nd) { + if(nodes.get(nodes.size()-1).getNodeID() != data.getNodeID() && allFloorsInvolved.contains(data.getFloor())) { + if (!validRetail.contains(data.getLongName())) { + Image image = new Image("/images/ThreeDim/retailICON.png"); + ImageView imageView = new ImageView(image); + imageView.setPreserveRatio(true); + imageView.setTranslateX(data.getxCoordinate() / 5 - 500); + imageView.setTranslateY(data.getyCoordinate() / 5 - 390); + imageView.setTranslateZ(zplace.get(data.getFloor()) - 25); + double scale = 0.04; + imageView.setScaleX(scale); + imageView.setScaleY(scale); + imageView.setScaleZ(scale); + imageView.getTransforms().add(new Rotate(90, Rotate.X_AXIS)); + retailICON.getChildren().add(imageView); + } + } + } + return retailICON; } - class SmartGroup extends Group { - Rotate r; - Transform t = new Rotate(); + private RotateGroup getSTAIcons() { - void rotateByX(int ang) { - r = new Rotate(ang, Rotate.X_AXIS); - t = t.createConcatenation(r); - this.getTransforms().clear(); - this.getTransforms().addAll(t); + RotateGroup staiICON = new RotateGroup(); + DatabaseController dbc = new DatabaseController(); + Set nd = dbc.getAllNodesOfType("STAI"); + for(NodeData data : nd) { + if (nodes.get(nodes.size() - 1).getNodeID() != data.getNodeID() && allFloorsInvolved.contains(data.getFloor())) { + Image image = new Image("/images/ThreeDim/stairsICON.png"); + ImageView imageView = new ImageView(image); + imageView.setPreserveRatio(true); + imageView.setTranslateX(data.getxCoordinate() / 5 - 1190); + imageView.setTranslateY(data.getyCoordinate() / 5 - 985); + imageView.setTranslateZ(zplace.get(data.getFloor()) - 20); + double scale = 0.01; + imageView.setScaleX(scale); + imageView.setScaleY(scale); + imageView.setScaleZ(scale); + imageView.getTransforms().add(new Rotate(90, Rotate.X_AXIS)); + staiICON.getChildren().add(imageView); + } } + return staiICON; + } - void rotateByY(int ang) { - r = new Rotate(ang, Rotate.Y_AXIS); - t = t.createConcatenation(r); - this.getTransforms().clear(); - this.getTransforms().addAll(t); + private RotateGroup getRESTIcons() { + + RotateGroup restICON = new RotateGroup(); + DatabaseController dbc = new DatabaseController(); + Set nd = dbc.getAllNodesOfType("REST"); + for(NodeData data : nd) { + if (nodes.get(nodes.size() - 1).getNodeID() != data.getNodeID() && allFloorsInvolved.contains(data.getFloor())) { + Image image = new Image("/images/ThreeDim/restICON.png"); + ImageView imageView = new ImageView(image); + imageView.setPreserveRatio(true); + imageView.setTranslateX(data.getxCoordinate() / 5 - 905); + imageView.setTranslateY(data.getyCoordinate() / 5 - 645); + imageView.setTranslateZ(zplace.get(data.getFloor()) - 20); + double scale = 0.015; + imageView.setScaleX(scale); + imageView.setScaleY(scale); + imageView.setScaleZ(scale); + imageView.getTransforms().add(new Rotate(90, Rotate.X_AXIS)); + restICON.getChildren().add(imageView); + } } + return restICON; + } + private ImageView getOverlay() { + Image image = new Image("/images/ThreeDim/overlay1.png"); + ImageView imageView = new ImageView(image); + imageView.setPreserveRatio(true); + imageView.setTranslateX(-442); + imageView.setTranslateY(-542); + imageView.setTranslateZ(0); + double scale = 0.67; + imageView.setScaleX(scale); + imageView.setScaleY(scale); + imageView.setScaleZ(scale); - void rotateByZ(int ang) { - r = new Rotate(ang, Rotate.Z_AXIS); - t = t.createConcatenation(r); - this.getTransforms().clear(); - this.getTransforms().addAll(t); + + return imageView; + } + + private void onElevClicked(Group elevIcons) { + if(elevToggle) { + elevIcons.getChildren().forEach(node -> {node.setVisible(false);}); + elevToggle = false; + } + else { + elevIcons.getChildren().forEach(node -> {node.setVisible(true);}); + elevToggle = true; } } - private void magical(NodeData startNode, NodeData endNode, SequentialTransition str, Shape s, SmartGroup group, Point3D point3, Point3D point4) { - HashMap zplace = new HashMap(); - double length; - zplace.put(1, 100); - zplace.put(2, 0); - zplace.put(3, -100); - zplace.put(4, -200); - zplace.put(5, -300); - if (endNode.getFloor() == nodes.get(0).getFloor()) { - PathTransition transitionEarth = new PathTransition(); - Line liner = new Line(point3.getX(), point3.getY(), point4.getX(), point4.getY()); - liner.setVisible(false); - group.getChildren().add(liner); - transitionEarth.setPath(liner); - transitionEarth.setNode(s); - transitionEarth.setInterpolator(Interpolator.LINEAR); - length = Math.sqrt(Math.pow(Math.abs(point4.getX() - point3.getX()), 2) + Math.pow(Math.abs(point4.getY() - point3.getY()), 2)); - transitionEarth.setDuration(Duration.seconds(getPathTime(length))); - transitionEarth.setInterpolator(Interpolator.LINEAR); - transitionEarth.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT); - transitionEarth.setCycleCount(1); - - str.getChildren().add(transitionEarth); - } else if (endNode.getNodeType().equals("ELEV")) { - length = Math.sqrt(Math.pow(Math.abs(endNode.getxCoordinate() - startNode.getxCoordinate()), 2) + Math.pow(Math.abs(endNode.getyCoordinate() - startNode.getyCoordinate()), 2)); - TranslateTransition translateTransition = new TranslateTransition(Duration.seconds(getPathTime(length)), s); //can change mph - translateTransition.setFromZ(zplace.get(startNode.getFloor()) - 50 - 30); - translateTransition.setFromX(startNode.getxCoordinate() / 5 - 247); - translateTransition.setFromY(startNode.getyCoordinate() / 5 - 148); - translateTransition.setToZ(zplace.get(endNode.getFloor()) - 50 - 30); - translateTransition.setToX(endNode.getxCoordinate() / 5 - 247); - translateTransition.setToY(endNode.getyCoordinate() / 5 - 148); - translateTransition.setCycleCount(1); - length = Math.sqrt(Math.pow(Math.abs(endNode.getxCoordinate() - startNode.getxCoordinate()), 2) + Math.pow(Math.abs(endNode.getyCoordinate() - startNode.getyCoordinate()), 2)); - translateTransition.setDuration(Duration.seconds(getPathTime(length))); - translateTransition.setInterpolator(Interpolator.LINEAR); - str.getChildren().add(translateTransition); - } else if (endNode.getFloor() == nodes.get(nodes.size() - 1).getFloor()) { - PathTransition transitionEarth = new PathTransition(); - Line liner = new Line(point3.getX(), point3.getY(), point4.getX(), point4.getY()); - liner.setVisible(false); - group.getChildren().add(liner); - transitionEarth.setPath(liner); - transitionEarth.setNode(s); - transitionEarth.setInterpolator(Interpolator.LINEAR); - length = Math.sqrt(Math.pow(Math.abs(point4.getX() - point3.getX()), 2) + Math.pow(Math.abs(point4.getY() - point3.getY()), 2)); - transitionEarth.setDuration(Duration.seconds(getPathTime(length))); - transitionEarth.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT); - transitionEarth.setCycleCount(1); - transitionEarth.setInterpolator(Interpolator.LINEAR); - str.getChildren().add(transitionEarth); + private void onFoodClicked(Group foodIcons) { + if(foodToggle) { ; + foodIcons.getChildren().forEach(node -> {node.setVisible(false);}); + foodToggle = false; + } + else { + foodIcons.getChildren().forEach(node -> {node.setVisible(true);}); + foodToggle = true; } } - private Slider prepareSlider() { - Slider slider = new Slider(); - slider.setMax(800); - slider.setMin(-400); - slider.setPrefWidth(300d); - slider.setLayoutX(100); - slider.setLayoutY(200); - slider.setShowTickLabels(true); - slider.setTranslateZ(5); - slider.setStyle("-fx-base: black"); - return slider; + private void onRestClicked(Group restIcons) { + if(restToggle) { + restIcons.getChildren().forEach(node -> {node.setVisible(false);}); + restToggle = false; + } + else { + restIcons.getChildren().forEach(node -> {node.setVisible(true);}); + restToggle = true; + } } - private double getPathTime(double lengthOfPath) { - return lengthOfPath / 200; + private void onRetailClicked(Group retlIcons) { + if(retlToggle) { + retlIcons.getChildren().forEach(node -> {node.setVisible(false);}); + retlToggle = false; + } + else { + retlIcons.getChildren().forEach(node -> {node.setVisible(true);}); + retlToggle = true; + } } - private Box getJuan(Image image, double zee) { - PhongMaterial material = new PhongMaterial(); - material.setDiffuseMap(image); - Box box = new Box(40, 0, 70); - box.setTranslateZ(zee + 100); - box.setTranslateX(250); - box.setTranslateY(100); - box.setMaterial(material); - return box; + private void onStairsClicked(Group stairIcons) { + if(staiToggle) { + stairIcons.getChildren().forEach(node -> {node.setVisible(false);}); + staiToggle = false; + } + else { + stairIcons.getChildren().forEach(node -> {node.setVisible(true);}); + staiToggle = true; + } } -} + private void onFloorMove(RotateGroup group, RotateGroup personGroup, RotateGroup numberGroup, NodeData begin) { + for(int i = 1; i <= 7; i++) { + if(Math.abs((personGroup.getTranslateZ() + floorDist * (2-begin.getFloor())) - (zplace.get(i))) <= 49) { + int finalI = i; + numberGroup.getChildren().stream().filter(node -> (node instanceof Box)) + .forEach( + node -> { + if(floorAddress.get(finalI - 1).equals(((PhongMaterial)(((Box) node).getMaterial())).getDiffuseMap().toString())) { + PhongMaterial material = new PhongMaterial(); + material.setDiffuseMap(new Image("images/ThreeDim/" + finalI + "H.png")); + floorAddress.set(finalI - 1,material.getDiffuseMap().toString()); + ((Box) node).setMaterial(material); + } + }); + } + if(Math.abs((personGroup.getTranslateZ() + floorDist * (2-begin.getFloor())) - (zplace.get(i))) > 49) { + int finalI1 = i; + numberGroup.getChildren().stream().filter(node -> (node instanceof Box)) + .forEach( + node -> { + if(floorAddress.get(finalI1 -1).equals(((PhongMaterial)(((Box) node).getMaterial())).getDiffuseMap().toString())) { + PhongMaterial material = new PhongMaterial(); + material.setDiffuseMap(new Image("images/ThreeDim/" + finalI1 + ".png")); + floorAddress.set(finalI1 -1,material.getDiffuseMap().toString()); + ((Box) node).setMaterial(material); + } + }); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/viewModels/RoomDisplayVm.java b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/viewModels/RoomDisplayVm.java new file mode 100644 index 00000000..65a86789 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/viewModels/RoomDisplayVm.java @@ -0,0 +1,70 @@ +package edu.wpi.cs3733.c20.teamS.pathDisplaying.viewModels; + +import edu.wpi.cs3733.c20.teamS.Settings; +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Vector2; +import edu.wpi.cs3733.c20.teamS.utilities.rx.ReactiveProperty; +import edu.wpi.cs3733.c20.teamS.utilities.rx.ReadOnlyReactiveProperty; +import edu.wpi.cs3733.c20.teamS.utilities.rx.RxAdaptors; +import javafx.scene.Parent; +import javafx.scene.paint.Color; +import javafx.scene.shape.Polygon; + +public class RoomDisplayVm extends Parent { + private static final Object UNIT = new Object(); + private final Room room; + private final Polygon mask; + private final RoomPopupUI popup; + private final ReadOnlyReactiveProperty isMouseOver; + private final ReactiveProperty normalFillColor = new ReactiveProperty<>(Color.TRANSPARENT); + private final ReactiveProperty highlightFillColor = new ReactiveProperty<>( + Settings.get().editRoomColorHighlight()); + + public RoomDisplayVm(Room room) { + if (room == null) ThrowHelper.illegalNull("room"); + + this.room = room; + Vector2 centroid = room.centroid(); + setTranslateX(centroid.x()); + setTranslateY(centroid.y()); + + mask = new Polygon(); + room.vertices().stream() + .map(vertex -> vertex.subtract(centroid)) + .forEach(vertex -> mask.getPoints().addAll(vertex.x(), vertex.y())); + getChildren().add(mask); + + popup = new RoomPopupUI(room); + popup.setVisible(false); + popup.setMouseTransparent(true); + getChildren().add(popup); + + isMouseOver = RxAdaptors.createMouseOverStream(this); + + initEventHandlers(); + updateHighlightState(); + } + + private void initEventHandlers() { + isMouseOver.changed().map(huh -> UNIT) + .mergeWith(normalFillColor.changed()) + .mergeWith(highlightFillColor.changed()) + .subscribe(u -> updateHighlightState()); + + isMouseOver.changed().map(huh -> RxAdaptors.UNIT) + .mergeWith(room.nameChanged()) + .map(u -> isMouseOver.value() && room.name() != null && !room.name().isEmpty()) + .filter(u -> Settings.get().showPopupsOnRoomMouseOver()) + .subscribe(popup::setVisible); + } + + private void updateHighlightState() { + Color fill = isMouseOver.value() ? + highlightFillColor.value() : + normalFillColor.value(); + mask.setFill(fill); + } + + +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/viewModels/RoomPopupUI.java b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/viewModels/RoomPopupUI.java new file mode 100644 index 00000000..7ed14c9c --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/pathDisplaying/viewModels/RoomPopupUI.java @@ -0,0 +1,78 @@ +package edu.wpi.cs3733.c20.teamS.pathDisplaying.viewModels; + +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.collisionMasks.Room; +import edu.wpi.cs3733.c20.teamS.utilities.rx.RxAdaptors; +import javafx.scene.Parent; +import javafx.scene.control.Label; +import javafx.scene.control.TextArea; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.scene.text.Font; + +/** + * Class responsible for rendering the popup information on the main pathfinding + * screen when you hover over a room. + */ +class RoomPopupUI extends Parent { + private final Room room; + private final VBox vbox = new VBox(); + private final ImageView iconView = new ImageView(); + private final Label nameLabel = new Label(); + private final HBox hbox = new HBox(); + private final TextArea descriptionTextArea = new TextArea(); + + public RoomPopupUI(Room room) { + if (room == null) ThrowHelper.illegalNull("room"); + + this.room = room; + tryInitImage(iconView); + iconView.setFitWidth(75); + iconView.setFitHeight(75); + nameLabel.setFont(new Font(nameLabel.getFont().getFamily(), 22)); + hbox.getChildren().addAll(iconView, nameLabel); + + vbox.getChildren().addAll(hbox, descriptionTextArea); + getChildren().add(vbox); + + updateUI(); + + room.nameChanged().map(n -> RxAdaptors.UNIT) + .mergeWith(room.descriptionChanged()) + .mergeWith(room.iconChanged()) + .subscribe(u -> updateUI()); + + RxAdaptors.propertyStream(nameLabel.widthProperty()) + .subscribe(descriptionTextArea::setPrefWidth); + } + + private void tryInitImage(ImageView imageView) { + if (room.icon() == null || room.icon().isEmpty()) + return; + + try { + Image image = new Image(room.icon()); + imageView.setImage(image); + } + catch (Exception ex) { + System.err.println("Failed to load icon " + room.icon() + " for room " + room.name()); + } + } + private void updateUI() { + nameLabel.setText(room.name()); + descriptionTextArea.setText(room.description()); + tryInitImage(iconView); + + boolean eitherNullOrEmpty = isNullOrEmptyWhenTrimmed(room.name()) || + isNullOrEmptyWhenTrimmed(room.description()); + nameLabel.setVisible(!eitherNullOrEmpty); + descriptionTextArea.setVisible(!eitherNullOrEmpty); + iconView.setVisible(!eitherNullOrEmpty); + } + + private static boolean isNullOrEmptyWhenTrimmed(String string) { + return string == null || string.trim().isEmpty(); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/pathfinding/WrittenInstructions.java b/src/main/java/edu/wpi/cs3733/c20/teamS/pathfinding/WrittenInstructions.java index fa9ad3ca..9a363d1e 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/pathfinding/WrittenInstructions.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/pathfinding/WrittenInstructions.java @@ -39,13 +39,18 @@ public List directions() { instructions.add("Go Straight For " + Math.round(savingDistance*ftRatio) + "FT " + "(" + Math.round(savingDistance*mRatio )+ "M)"); } if (path.size()>2) { + for (int i = 0; i < path.size()-2 ; i++) { + if(i == 0){ + instructions.add("On Floor " + path.get(i).getFloor()); + } if (directionOfPoint(path.get(i), path.get(i + 1), path.get(i + 2)) == 1) { if(path.get(i).getNodeType().equals("ELEV") && !path.get(i+1).getNodeType().equals("ELEV") && i != 0){ instructions.add("Take The Elevator To Floor " + path.get(i+1).getFloor() ); + instructions.add("On Floor " + path.get(i+1).getFloor()); } if(distance(path.get(i), path.get(i+1)) < 5){ @@ -66,6 +71,7 @@ else if(path.get(i).getNodeType().equals("STAI") && !path.get(i+1).getNodeType() if(path.get(i).getNodeType().equals("ELEV") && !path.get(i+1).getNodeType().equals("ELEV") && i != 0){ instructions.add("Take The Elevator To Floor " + path.get(i+1).getFloor()); + instructions.add("On Floor " + path.get(i+1).getFloor()); } if(distance(path.get(i), path.get(i+1)) < 5){ @@ -95,8 +101,9 @@ else if(path.get(i).getNodeType().equals("STAI") && !path.get(i+1).getNodeType() } if (path.get(path.size()-2).getNodeType().equals("ELEV")){ instructions.add("Take The Elevator To Floor " + path.get(path.size()-1).getFloor() + ", Then Go Straight"); + instructions.add("Floor" + path.get(path.size()-1).getFloor()); } - if(instructions.isEmpty()){ + if(instructions.size() == 1){ int pathSize = path.size(); int sub = pathSize-1; diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/serviceRequests/SelectServiceController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/serviceRequests/SelectServiceController.java index a7786d4e..7f347632 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/serviceRequests/SelectServiceController.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/serviceRequests/SelectServiceController.java @@ -2,24 +2,20 @@ import com.jfoenix.controls.JFXButton; -import edu.wpi.cs3733.c20.teamS.GiftRequest; +import edu.wpi.c20.teamU.FlowerRequest.RunFlowerRequest; +import edu.wpi.cs3733.c20.teamR.AppointmentRequest; +import edu.wpi.cs3733.c20.teamS.GiftRequest.GiftRequest; import edu.wpi.cs3733.c20.teamS.app.DialogEvent; +import edu.wpi.cs3733.c20.teamV.vVolesAPI.InterpreterRequester; import foodRequest.FoodRequest; import foodRequest.ServiceException; import io.reactivex.rxjava3.subjects.PublishSubject; import edu.wpi.cs3733.c20.teamS.app.serviceRequests.*; import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.scene.Scene; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.layout.AnchorPane; import javafx.stage.Modality; import javafx.stage.Stage; -import javax.swing.*; -import javax.xml.ws.Service; - public class SelectServiceController { private Stage stage; private Employee loggedIn; @@ -71,11 +67,19 @@ public class SelectServiceController { this.stage.close(); } @FXML void onServiceTechClicked(ActionEvent event){ - Stage serviceTechStage = new Stage(); - serviceTechStage.initModality(Modality.WINDOW_MODAL); +// Stage serviceTechStage = new Stage(); +// serviceTechStage.initModality(Modality.WINDOW_MODAL); +// +// ServiceTechRequestScreen.showDialog(loggedIn).subscribe(); +// this.stage.close(); - ServiceTechRequestScreen.showDialog(loggedIn).subscribe(); - this.stage.close(); + AppointmentRequest request = new AppointmentRequest(); + try{ + request.run((int)this.stage.getX()-5,(int)this.stage.getY()-5,800,800,"","SHALL00201", null); + } + catch (Exception e){ + System.out.println("Error running appointment request\n" + e.getMessage()); + } } @FXML void onLaundryClicked(ActionEvent event){ @@ -97,11 +101,13 @@ public class SelectServiceController { } @FXML void onFloristClicked(ActionEvent event){ - Stage floristStage = new Stage(); - floristStage.initModality(Modality.WINDOW_MODAL); - - FloristRequestScreen.showDialog(loggedIn).subscribe(); - this.stage.close(); + RunFlowerRequest request = new RunFlowerRequest(); + try{ + request.run(0,0,1600,900,"", "SHALL00501", "SHALL00402"); + } + catch(Exception e){ + System.out.println(e.getMessage()); + } } @FXML void onRideClicked(ActionEvent event){ @@ -120,10 +126,8 @@ public class SelectServiceController { this.stage.close(); } + @FXML void onGiftClicked(ActionEvent event){ -// Stage janitorStage = new Stage(); -// janitorStage.initModality(Modality.WINDOW_MODAL); -// GiftRequestScreen.showDialog(loggedIn).subscribe(); GiftRequest request = new GiftRequest(); try{ request.run(0,0,"","Room250"); @@ -138,7 +142,7 @@ public class SelectServiceController { @FXML void onFoodClicked(ActionEvent event) throws ServiceException { FoodRequest foodRequest = new FoodRequest(); - foodRequest.run(0,0,500,500, null, "f","h"); + foodRequest.run(0,0,1900,1000, null, "f","h"); } /** diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/serviceRequests/SelectServiceScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/serviceRequests/SelectServiceScreen.java index a70a2793..ba8aed60 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/serviceRequests/SelectServiceScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/serviceRequests/SelectServiceScreen.java @@ -1,6 +1,9 @@ package edu.wpi.cs3733.c20.teamS.serviceRequests; +import edu.wpi.cs3733.c20.teamS.BaseScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -40,6 +43,8 @@ private SelectServiceScreen(Employee employee) { private void show() { stage.setScene(scene); + Settings.openWindows.add(this.stage); + BaseScreen.puggy.register(scene, Event.ANY); stage.show(); } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/twoFactor/TwoFactorScreen.java b/src/main/java/edu/wpi/cs3733/c20/teamS/twoFactor/TwoFactorScreen.java index 739d496f..eefac0ae 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/twoFactor/TwoFactorScreen.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/twoFactor/TwoFactorScreen.java @@ -1,14 +1,20 @@ package edu.wpi.cs3733.c20.teamS.twoFactor; +import edu.wpi.cs3733.c20.teamS.BaseScreen; import edu.wpi.cs3733.c20.teamS.Editing.MapEditingScreen; +import edu.wpi.cs3733.c20.teamS.Settings; import edu.wpi.cs3733.c20.teamS.database.DatabaseController; import edu.wpi.cs3733.c20.teamS.database.EmployeeData; import edu.wpi.cs3733.c20.teamS.serviceRequests.Employee; import edu.wpi.cs3733.c20.teamS.utilities.TFAThread; +import javafx.event.Event; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; +import javafx.stage.StageStyle; + import java.io.IOException; +import java.util.Map; public class TwoFactorScreen { private TwoFactorScreenController tfa; @@ -23,8 +29,8 @@ public class TwoFactorScreen { public TwoFactorScreen(Stage passedStage, Employee employee) { this.loggedIn = employee; + Settings.get().setLoggedIn(this.loggedIn); toPass = passedStage; - DatabaseController dbc = new DatabaseController(); this.stage = new Stage(); FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/TwoFactorScreen.fxml")); loader.setControllerFactory(c -> { @@ -42,25 +48,24 @@ public TwoFactorScreen(Stage passedStage, Employee employee) { } this.show(); - //stage.setFullScreen(false); + stage.setResizable(false); stage.setTitle("Two Factor Authentication"); - - //stage.initModality(Modality.APPLICATION_MODAL); stage.centerOnScreen(); } public void show() { stage.setScene(scene); - //stage.setMaximized(f); - //stage.initStyle(StageStyle.UNDECORATED); + BaseScreen.puggy.register(scene, Event.ANY); + stage.initStyle(StageStyle.UNDECORATED); + Settings.openWindows.add(stage); stage.show(); } public void passedTFA(){ - - MapEditingScreen mes = new MapEditingScreen(toPass, loggedIn); + Settings.get().setLoggedIn(loggedIn); + MapEditingScreen mes = new MapEditingScreen(); this.stage.close(); } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/twoFactor/TwoFactorScreenController.java b/src/main/java/edu/wpi/cs3733/c20/teamS/twoFactor/TwoFactorScreenController.java index 9ee77e8c..4bcc9e05 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/twoFactor/TwoFactorScreenController.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/twoFactor/TwoFactorScreenController.java @@ -77,23 +77,16 @@ void onATTClicked(ActionEvent event) { @FXML void onEnterClicked(ActionEvent event) { - - if(Integer.parseInt(tfaCodeField.getText()) == tfaScreen.tfaCode){ tfaScreen.passedTFA(); }else{ descLabel.setText("Incorrect code"); tfaCodeField.setStyle("-fx-background-color:RED"); } - - - } @FXML void onSendClicked(ActionEvent event) { - - System.out.println("Carrier selected is: " + carrierSelector.getText()); if(carrierSelector.getText().equals("Carrier")){ System.out.println("No carrier selected"); @@ -110,16 +103,11 @@ void onSendClicked(ActionEvent event) { carrierSelector.setDisable(true); descLabel.setText("Text sent to number on file"); - - - } public PublishSubject> dialogCompleted_; public Observable> dialogCompleted() { return dialogCompleted_; } - //private final PublishSubject> dialogCompleted_ = PublishSubject.create(); - } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/FireWatchDog.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/FireWatchDog.java new file mode 100644 index 00000000..14c27693 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/FireWatchDog.java @@ -0,0 +1,46 @@ +package edu.wpi.cs3733.c20.teamS.utilities; + +import javafx.animation.Animation; +import javafx.animation.KeyFrame; +import javafx.animation.Timeline; +import javafx.event.Event; +import javafx.event.EventHandler; +import javafx.event.EventType; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.util.Duration; +import java.util.Observable; + +public class FireWatchDog{ + private final Timeline idleTimeline; + //private final EventHandler userEventHandler; + private final Runnable notifier; + + public FireWatchDog(Duration timeout, Runnable notifier){ + this.notifier = notifier; + idleTimeline = new Timeline(new KeyFrame(timeout,e->notifier.run())); + idleTimeline.setCycleCount(Animation.INDEFINITE); + //idleTimeline.getKeyFrames(). + //userEventHandler = e->notIdle(); + idleTimeline.playFromStart(); + + } + + public void changeTimeout(int duration){ + this.idleTimeline.getKeyFrames().clear(); + this.idleTimeline.getKeyFrames().add(new KeyFrame(new Duration(duration),e->notifier.run())); + } + + + public void pause(){ + idleTimeline.pause(); + } + public void play(){ + idleTimeline.playFromStart(); + } + + + + +} + diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/SendEmailDirectionsThread.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/SendEmailDirectionsThread.java index afa1c7ea..fc58b12c 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/SendEmailDirectionsThread.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/SendEmailDirectionsThread.java @@ -1,7 +1,6 @@ package edu.wpi.cs3733.c20.teamS.utilities; import java.util.List; -import java.util.Set; public class SendEmailDirectionsThread extends Thread { List directions; @@ -18,7 +17,7 @@ public SendEmailDirectionsThread(List directions, String email){ public void run() { String allDirections = ""; for(String d : directions){ - allDirections = allDirections + d +" - "; + allDirections = allDirections + d +" \n"; } Mailer.sendMail(allDirections,"Directions from Faulkner Hospital",email); diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/SendTextDirectionsThread.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/SendTextDirectionsThread.java index eedf8a42..ff471fca 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/SendTextDirectionsThread.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/SendTextDirectionsThread.java @@ -1,9 +1,6 @@ package edu.wpi.cs3733.c20.teamS.utilities; -import edu.wpi.cs3733.c20.teamS.SendTextDirectionsScreen; - import java.util.List; -import java.util.Set; public class SendTextDirectionsThread extends Thread { List directions; @@ -21,7 +18,7 @@ public SendTextDirectionsThread(List directions, String number, String c public void run() { String allDirections = ""; for(String d : directions){ - allDirections = allDirections + d +" - "; + allDirections = allDirections + d +" \n "; } Mailer.sendTextToCarrier(allDirections,"Directions from Faulkner Hospital",number,carrier); diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/TweetBoxTest.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/TweetBoxTest.java deleted file mode 100644 index baf58e76..00000000 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/TweetBoxTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package edu.wpi.cs3733.c20.teamS.utilities; - -import javafx.application.Application; -import javafx.stage.Stage; - -public class TweetBoxTest extends Application { - @Override - public void start(Stage primaryStage) throws Exception { - Tweetbox tb = new Tweetbox(); - - //WeatherBox.getCurrentWeather(); - //tb.getTweets(); - } -} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/Tweetbox.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/Tweetbox.java index d90a42be..2cd4fa37 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/Tweetbox.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/Tweetbox.java @@ -17,9 +17,9 @@ public static List getTweets(String usernameWithAt){ String handle = usernameWithAt; List statuses = twitter.getUserTimeline(handle); - System.out.println("Showing @" + handle+ "'s home timeline."); + //System.out.println("Showing @" + handle+ "'s home timeline."); for (Status status : statuses) { - System.out.println("@" + status.getUser().getScreenName() + " - " + status.getText()); + //System.out.println("@" + status.getUser().getScreenName() + " - " + status.getText()); stringStatus.add("@" + status.getUser().getScreenName() + " - " + status.getText()); } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/UIWatchPug.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/UIWatchPug.java new file mode 100644 index 00000000..5204a2c2 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/UIWatchPug.java @@ -0,0 +1,65 @@ +package edu.wpi.cs3733.c20.teamS.utilities; + +import javafx.animation.Animation; +import javafx.animation.KeyFrame; +import javafx.animation.Timeline; +import javafx.event.Event; +import javafx.event.EventHandler; +import javafx.event.EventType; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.util.Duration; +import java.util.Observable; + +public class UIWatchPug{ + private final Timeline idleTimeline; + private final EventHandler userEventHandler; + private final Runnable notifier; + + public UIWatchPug(Duration timeout, Runnable notifier){ + this.notifier = notifier; + idleTimeline = new Timeline(new KeyFrame(timeout,e->notifier.run())); + idleTimeline.setCycleCount(Animation.INDEFINITE); + //idleTimeline.getKeyFrames(). + userEventHandler = e->notIdle(); + idleTimeline.playFromStart(); + + } + + public void changeTimeout(int duration){ + this.idleTimeline.getKeyFrames().clear(); + this.idleTimeline.getKeyFrames().add(new KeyFrame(new Duration(duration),e->notifier.run())); + } + + public void notIdle() { + if (idleTimeline.getStatus() == Animation.Status.RUNNING) { + idleTimeline.playFromStart(); + } + } + + public void register(Scene scene, EventType eventType) { + scene.addEventFilter(eventType, userEventHandler); + } + + public void register(Node node, EventType eventType) { + node.addEventFilter(eventType, userEventHandler); + } + + public void unregister(Scene scene, EventType eventType) { + scene.removeEventFilter(eventType, userEventHandler); + } + + public void unregister(Node node, EventType eventType) { + node.removeEventFilter(eventType, userEventHandler); + } + public void pause(){ + idleTimeline.pause(); + } + public void play(){ + idleTimeline.playFromStart(); + } + + + + +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/Numerics.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/numerics/Numerics.java similarity index 81% rename from src/main/java/edu/wpi/cs3733/c20/teamS/utilities/Numerics.java rename to src/main/java/edu/wpi/cs3733/c20/teamS/utilities/numerics/Numerics.java index 064c1054..9a01187a 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/Numerics.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/numerics/Numerics.java @@ -1,4 +1,4 @@ -package edu.wpi.cs3733.c20.teamS.utilities; +package edu.wpi.cs3733.c20.teamS.utilities.numerics; public final class Numerics { private Numerics() {} @@ -23,6 +23,17 @@ public static int clamp(int value, int min, int max) { return value; } + public static double clamp(double value, double min, double max) { + if (min > max) + throw new IllegalArgumentException("'min' can't be greater than 'max'."); + + if (value < min) + return min; + if (value > max) + return max; + return value; + } + public static double distance(double x1, double y1, double x2, double y2) { double xOffset = x1 - x2; double yOffset = y1 - y2; diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/Vector2.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/numerics/Vector2.java similarity index 98% rename from src/main/java/edu/wpi/cs3733/c20/teamS/utilities/Vector2.java rename to src/main/java/edu/wpi/cs3733/c20/teamS/utilities/numerics/Vector2.java index 62df1dc1..7be62312 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/Vector2.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/numerics/Vector2.java @@ -1,4 +1,4 @@ -package edu.wpi.cs3733.c20.teamS.utilities; +package edu.wpi.cs3733.c20.teamS.utilities.numerics; import java.util.Objects; @@ -211,4 +211,6 @@ public boolean equals(Vector2 other, double epsilon) { public String toString() { return "(" + x_ + ", " + y_ + ")"; } + + public static final Vector2 ZERO = new Vector2(0, 0); } diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/DisposableBase.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/DisposableBase.java new file mode 100644 index 00000000..a9404797 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/DisposableBase.java @@ -0,0 +1,20 @@ +package edu.wpi.cs3733.c20.teamS.utilities.rx; + +import io.reactivex.rxjava3.disposables.Disposable; + +public abstract class DisposableBase implements Disposable { + private boolean isDisposed = false; + + public final void dispose() { + if (isDisposed) + return; + onDispose(); + isDisposed = true; + } + + public final boolean isDisposed() { + return isDisposed; + } + + protected abstract void onDispose(); +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/DisposableSelector.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/DisposableSelector.java new file mode 100644 index 00000000..2ae76e78 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/DisposableSelector.java @@ -0,0 +1,31 @@ +package edu.wpi.cs3733.c20.teamS.utilities.rx; + +import io.reactivex.rxjava3.disposables.Disposable; + +import java.util.function.Supplier; + +/** + * When you have a field that is disposable, and you want to make sure that the previous value is + * disposed when it is assigned a new value, use this. + * @param + */ +public final class DisposableSelector { + private T current; + + public T current() { + return current; + } + public void setCurrent(T value) { + // Reference equality check intended. + if (current == value) + return; + if (current != null) + current.dispose(); + current = value; + } + public void setCurrent(Supplier factory) { + if (current != null) + current.dispose(); + current = factory.get(); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/ReactiveProperty.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/ReactiveProperty.java similarity index 78% rename from src/main/java/edu/wpi/cs3733/c20/teamS/utilities/ReactiveProperty.java rename to src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/ReactiveProperty.java index c0c1c7b6..940be8d0 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/ReactiveProperty.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/ReactiveProperty.java @@ -1,4 +1,4 @@ -package edu.wpi.cs3733.c20.teamS.utilities; +package edu.wpi.cs3733.c20.teamS.utilities.rx; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; @@ -12,6 +12,7 @@ public final class ReactiveProperty { private final PublishSubject changed = PublishSubject.create(); private T value; + private ReadOnlyReactiveProperty readOnlyWrapper; public ReactiveProperty(T value) { this.value = value; @@ -44,4 +45,10 @@ public void setValue(T value) { public Observable changed() { return changed; } + + public ReadOnlyReactiveProperty asReadOnly() { + if (readOnlyWrapper == null) + readOnlyWrapper = new ReadOnlyReactiveProperty<>(this); + return readOnlyWrapper; + } } \ No newline at end of file diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/ReadOnlyReactiveProperty.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/ReadOnlyReactiveProperty.java new file mode 100644 index 00000000..3d023210 --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/ReadOnlyReactiveProperty.java @@ -0,0 +1,24 @@ +package edu.wpi.cs3733.c20.teamS.utilities.rx; + +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import io.reactivex.rxjava3.core.Observable; + +/** + * A read-only wrapper around a reactive property. + * @param + */ +public class ReadOnlyReactiveProperty { + private final ReactiveProperty inner; + public ReadOnlyReactiveProperty(ReactiveProperty inner) { + if (inner == null) ThrowHelper.illegalNull("inner"); + + this.inner = inner; + } + + public T value() { + return inner.value(); + } + public Observable changed() { + return inner.changed(); + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/RxAdaptors.java b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/RxAdaptors.java new file mode 100644 index 00000000..61a5c9df --- /dev/null +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/utilities/rx/RxAdaptors.java @@ -0,0 +1,101 @@ +package edu.wpi.cs3733.c20.teamS.utilities.rx; + +import edu.wpi.cs3733.c20.teamS.ThrowHelper; +import edu.wpi.cs3733.c20.teamS.utilities.numerics.Vector2; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.PublishSubject; +import io.reactivex.rxjava3.subjects.Subject; +import javafx.beans.property.ReadOnlyDoubleProperty; +import javafx.beans.property.ReadOnlyProperty; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.collections.ObservableSet; +import javafx.collections.SetChangeListener; +import javafx.event.Event; +import javafx.event.EventHandler; +import javafx.scene.Node; + +import java.util.function.Consumer; + +/** + * Contains adaptor methods for using RX streams with other systems, such as JavaFX events and properties. + */ +public final class RxAdaptors { + public static final Object UNIT = new Object(); + private RxAdaptors() {} + + public static Observable propertyStream(ReadOnlyProperty property) { + if (property == null) ThrowHelper.illegalNull("property"); + + Subject subject = PublishSubject.create(); + property.addListener((sender, previous, current) -> subject.onNext(current)); + + return subject; + } + + public static Observable propertyStream(ReadOnlyDoubleProperty property) { + if (property == null) ThrowHelper.illegalNull("property"); + + Subject subject = PublishSubject.create(); + property.addListener((sender, previous, current) -> subject.onNext(current.doubleValue())); + + return subject; + } + + /** + * Creates an observable stream from the setter for a JavaFX event. + * @param setListener The function that you call to set an event handler, for example, setOnMouseClicked(...) + * @param The type of event. + * @return An observable stream for the event. + */ + public static Observable eventStream(Consumer> setListener) { + PublishSubject result = PublishSubject.create(); + setListener.accept(e -> result.onNext(e)); + return result; + } + + /** + * Creates an isMouseOver event stream for the specified ui element. + * @param uiElement The element to create an isMouseOver stream for. + * @return An observable stream that pushes an event whenever the mouse enters or exits the ui element. + * True is pushed whenever the mouse is over, false whenever it is not. + */ + public static ReadOnlyReactiveProperty createMouseOverStream(Node uiElement) { + if (uiElement == null) ThrowHelper.illegalNull("uiElement"); + + ReactiveProperty result = new ReactiveProperty<>(false); + uiElement.setOnMouseEntered(e -> result.setValue(true)); + uiElement.setOnMouseExited(e -> result.setValue(false)); + + return result.asReadOnly(); + } + + /** + * Creates an observable mouse-dragged event stream that reports the position in parent-coordinates. + * @param uiElement The ui element to create the mouse-dragged stream for. + * @return An observable stream that reports the mouse position in parent-coordinates. + */ + public static Observable createMouseDraggedStream(Node uiElement) { + return eventStream(uiElement::setOnMouseDragged) + .map(e -> uiElement.localToParent(e.getX(), e.getY())) + .map(point -> new Vector2(point.getX(), point.getY())); + } + + public static Observable> fromObservableSet(ObservableSet set) { + if (set == null) ThrowHelper.illegalNull("set"); + + PublishSubject> subject = PublishSubject.create(); + set.addListener(subject::onNext); + + return subject; + } + + public static Observable> fromObservableList(ObservableList list) { + if (list == null) ThrowHelper.illegalNull("list"); + + PublishSubject> subject = PublishSubject.create(); + list.addListener(subject::onNext); + + return subject; + } +} diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/widgets/AutoComplete.java b/src/main/java/edu/wpi/cs3733/c20/teamS/widgets/AutoComplete.java index 7eb3c16a..aaee6cbb 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/widgets/AutoComplete.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/widgets/AutoComplete.java @@ -1,14 +1,9 @@ package edu.wpi.cs3733.c20.teamS.widgets; import edu.wpi.cs3733.c20.teamS.ThrowHelper; -import io.reactivex.rxjava3.annotations.NonNull; +import edu.wpi.cs3733.c20.teamS.utilities.rx.RxAdaptors; import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.disposables.DisposableContainer; -import io.reactivex.rxjava3.subjects.PublishSubject; -import io.reactivex.rxjava3.subjects.Subject; -import io.reactivex.rxjava3.subscribers.DisposableSubscriber; import javafx.beans.property.Property; import javafx.scene.control.ComboBox; import javafx.scene.control.TextField; @@ -34,10 +29,7 @@ private static Collection wordLookup(Collection dictionary, Stri } public static Observable propertyStream(Property property) { - Subject subject = PublishSubject.create(); - property.addListener((sender, previous, current) -> subject.onNext(current)); - - return subject; + return RxAdaptors.propertyStream(property); } /** diff --git a/src/main/java/edu/wpi/cs3733/c20/teamS/widgets/LookupResult.java b/src/main/java/edu/wpi/cs3733/c20/teamS/widgets/LookupResult.java index 81d1dfc4..6e87434b 100644 --- a/src/main/java/edu/wpi/cs3733/c20/teamS/widgets/LookupResult.java +++ b/src/main/java/edu/wpi/cs3733/c20/teamS/widgets/LookupResult.java @@ -4,7 +4,7 @@ public final class LookupResult { private final T value; private final String text; - LookupResult(String text, T value) { + public LookupResult(String text, T value) { this.text = text; this.value = value; } diff --git a/src/main/resources/FXML/AboutMe.fxml b/src/main/resources/FXML/AboutMe.fxml index 10f6f93d..479d0fff 100644 --- a/src/main/resources/FXML/AboutMe.fxml +++ b/src/main/resources/FXML/AboutMe.fxml @@ -6,16 +6,21 @@ - + - + - + - + - + + + + + + diff --git a/src/main/resources/FXML/ActiveServiceRequestScreen.fxml b/src/main/resources/FXML/ActiveServiceRequestScreen.fxml index 5293ff14..de7ed822 100644 --- a/src/main/resources/FXML/ActiveServiceRequestScreen.fxml +++ b/src/main/resources/FXML/ActiveServiceRequestScreen.fxml @@ -7,7 +7,7 @@ - + @@ -27,8 +27,9 @@ - + diff --git a/src/main/resources/FXML/AddCapabilityScreen.fxml b/src/main/resources/FXML/AddCapabilityScreen.fxml index 134808f7..aceabb35 100644 --- a/src/main/resources/FXML/AddCapabilityScreen.fxml +++ b/src/main/resources/FXML/AddCapabilityScreen.fxml @@ -11,8 +11,7 @@ - - + @@ -43,7 +42,7 @@ - - + + diff --git a/src/main/resources/FXML/AddEmployeeScreen.fxml b/src/main/resources/FXML/AddEmployeeScreen.fxml index a77ac979..1cffea1c 100644 --- a/src/main/resources/FXML/AddEmployeeScreen.fxml +++ b/src/main/resources/FXML/AddEmployeeScreen.fxml @@ -9,7 +9,7 @@ - + @@ -39,7 +39,7 @@ - - + + diff --git a/src/main/resources/FXML/AssignEmployeeScreen.fxml b/src/main/resources/FXML/AssignEmployeeScreen.fxml new file mode 100644 index 00000000..cb05679d --- /dev/null +++ b/src/main/resources/FXML/AssignEmployeeScreen.fxml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/FXML/CapabilityEditingScreen.fxml b/src/main/resources/FXML/CapabilityEditingScreen.fxml index e0464ce9..497c53f1 100644 --- a/src/main/resources/FXML/CapabilityEditingScreen.fxml +++ b/src/main/resources/FXML/CapabilityEditingScreen.fxml @@ -11,8 +11,7 @@ - - + @@ -43,8 +42,8 @@ - - - + + + diff --git a/src/main/resources/FXML/CreditsPage.fxml b/src/main/resources/FXML/CreditsPage.fxml new file mode 100644 index 00000000..7ecb2240 --- /dev/null +++ b/src/main/resources/FXML/CreditsPage.fxml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/FXML/EmergencyAlert.fxml b/src/main/resources/FXML/EmergencyAlert.fxml new file mode 100644 index 00000000..da3b84c0 --- /dev/null +++ b/src/main/resources/FXML/EmergencyAlert.fxml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + +
+
+
+ + + +
+ + + + + + + + +
+
diff --git a/src/main/resources/FXML/EmployeeEditingScreen.fxml b/src/main/resources/FXML/EmployeeEditingScreen.fxml index 70741c59..0a6a9f10 100644 --- a/src/main/resources/FXML/EmployeeEditingScreen.fxml +++ b/src/main/resources/FXML/EmployeeEditingScreen.fxml @@ -6,32 +6,36 @@ + - + - + - - - - - - - + + + + + + + - - diff --git a/src/main/resources/FXML/NodeEditScreen.fxml b/src/main/resources/FXML/NodeEditScreen.fxml index ba18469f..0530859c 100644 --- a/src/main/resources/FXML/NodeEditScreen.fxml +++ b/src/main/resources/FXML/NodeEditScreen.fxml @@ -15,14 +15,14 @@ - + -