Schedule-Creator

Java GUI to create schedules for UNCG students
git clone git://git.wrycode.com/wrycode/archive/Schedule-Creator.git
Log | Files | Refs | README

commit 451aaa4c2a723a38f73abead0b2d5f4a189d0767
parent 49b5145a282d0dabcc809a099dcc3bb7af0d2de2
Author: Ilyass Sfar <42755577+cloud0x9@users.noreply.github.com>
Date:   Mon, 27 Apr 2020 19:42:23 -0400

Allow User to Update DB with drag and drop (#71)

* Add view and controller for user updated db.

* Added file name and content fail safes.

* Style Guide

* Remove advisor button(doesn't go anywhere), and improve drag and drop feature.
Diffstat:
MScheduleCreator/Admin.java | 20++++++++++----------
MScheduleCreator/Tests.java | 4++--
MScheduleCreator/controllers/PrimaryController.java | 18+++++++++++++++---
AScheduleCreator/controllers/UserUpdatedDBController.java | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AScheduleCreator/resources/views/UserUpdatedDB.fxml | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MScheduleCreator/resources/views/primary.fxml | 120++++++++++++++++++++++++++++++++++++++++----------------------------------------
6 files changed, 264 insertions(+), 75 deletions(-)

diff --git a/ScheduleCreator/Admin.java b/ScheduleCreator/Admin.java @@ -1,5 +1,13 @@ package ScheduleCreator; +/** + * Utility classes for generating the DB (these do NOT work at runtime) TODO: - + * pull out hardcoded paths - + * + * @author Nick Econopouly, Jamison Valentine, Ilyass Sfar + * + * Last Updated: 3/16/2020 + */ import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -15,14 +23,6 @@ import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; -/** - * Utility classes for generating the DB (these do NOT work at runtime) TODO: - - * pull out hardcoded paths - - * - * @author Nick Econopouly, Jamison Valentine, Ilyass Sfar - * - * Last Updated: 3/16/2020 - */ public class Admin { /** @@ -56,7 +56,7 @@ public class Admin { String[] pathnames = rawDir.list(); // 'pathnames.length - 1' so we don't count the raw directory itself - try ( FileWriter outputFile = new FileWriter(semesterListFile.getPath())) { + try (FileWriter outputFile = new FileWriter(semesterListFile.getPath())) { for (String pathname : pathnames) { // add filename to list of semesters outputFile.append(pathname); @@ -161,7 +161,7 @@ public class Admin { } } File outputFile = new File(_outputFilepath); - try ( FileWriter output = new FileWriter(outputFile)) { + try (FileWriter output = new FileWriter(outputFile)) { for (String s : allCourses) { output.append(s + '\n'); } diff --git a/ScheduleCreator/Tests.java b/ScheduleCreator/Tests.java @@ -19,9 +19,9 @@ public class Tests { // uncomment and run this once when we add a new semester // Admin.regenDB(); - + //test validate method - emailMethodTestData(); + emailMethodTestData(); } diff --git a/ScheduleCreator/controllers/PrimaryController.java b/ScheduleCreator/controllers/PrimaryController.java @@ -38,9 +38,9 @@ public class PrimaryController implements Initializable { @FXML private GridPane mainBox; @FXML - private HBox schedMenuItem, advMenuItem, regMenuItem, currentMenuItem; + private HBox schedMenuItem, regMenuItem, currentMenuItem, dbItem; @FXML - private Label schedMenuItemLabel, advMenuItemLabel, regMenuItemLabel; + private Label schedMenuItemLabel, regMenuItemLabel, dbItemLabel; private HashMap<HBox, Label> menuItems = new HashMap(); private boolean showMenu = false; @@ -59,6 +59,18 @@ public class PrimaryController implements Initializable { } /** + * Change current view to the user updated database screen. + * + * @throws Exception + */ + public void changeToDBScreen() throws Exception { + Parent root = FXMLLoader.load(getClass().getResource("/ScheduleCreator/resources/views/UserUpdatedDB.fxml")); + mainContent.getChildren().clear(); + mainContent.getChildren().add(root); + this.setCurrentItem(this.dbItem); + } + + /** * Sets the current menu item to the given argument. * * @param _menuItem @@ -171,8 +183,8 @@ public class PrimaryController implements Initializable { public void initialize(URL url, ResourceBundle rb) { try { this.menuItems.put(this.schedMenuItem, this.schedMenuItemLabel); - this.menuItems.put(this.advMenuItem, this.advMenuItemLabel); this.menuItems.put(this.regMenuItem, this.regMenuItemLabel); + this.menuItems.put(this.dbItem, this.dbItemLabel); this.mainBox.getColumnConstraints().get(0).setMaxWidth(0); this.changeToSelectCourses(); System.out.println("initialized"); diff --git a/ScheduleCreator/controllers/UserUpdatedDBController.java b/ScheduleCreator/controllers/UserUpdatedDBController.java @@ -0,0 +1,119 @@ +package ScheduleCreator.controllers; + +/** + * Allows user to add new semesters via drag and drop in the UI. + * + * @author Ilyass Sfar + * + * Last Updated: 4/23/2020 + */ +import ScheduleCreator.Admin; +import java.io.File; +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; +import javafx.scene.input.DragEvent; +import javafx.scene.input.Dragboard; +import javafx.scene.input.TransferMode; + +public class UserUpdatedDBController extends Admin { + + //used to test if a file actaully contains course infromation of not before proceeding + Pattern checkCourseData = Pattern.compile("(.+?(?= - (?:[0-9]{5}))[ ])|([ ][0-9]{5}[ ])|([ ]\\b[A-Z]{3}\\b.\\b[0-9]{3}\\b.+ [0-9]{2}\\b)|([\\t](?:(?:(?:[0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9].(?:[AaPp][Mm])\\\\b).-.(?:[0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9].(?:[AaPp][Mm])\\b))|(\\b([\\t](TR\\b|MW\\b|MWF\\b|M\\b|T\\b|W\\b|R\\b|F\\b|(TBA.*TBA\\b)))\\b)|(\\t.*([0-9]{3}))(?=\\t[A-z]{3} [0-9]{2})|((?=(\\tLecture|\\tLab|\\tIndividual Study|\\tSeminar|\\tClinical|Colloquia|\\tDissertation or Thesis|\\tEnsemble|\\tInternship, Field Exp, Coop Ed|\\tLecture and lab|\\tPerformance|\\tPhysical Activity|\\tPracticum - Dlvrd Ind Setting|\\tPracticum - Dlvrd Org Course|\\tRecitations|\\tStudent Teaching|\\tStudio|\\tLecture and Lab|\\tDissertation or Thesis)).+?(?<=(((\\(P\\)E-mail)|(\\(P\\))|(TBA)))))"); + //used to test if the file name is inline with the naming convetions used by the db + Pattern checkFileName = Pattern.compile("((fall|spring|winter|summer)([0-9]{4}))(\\.[A-z]*|(?!.))"); + + /** + * When a file is dropped on the scene, it is checked and if it passes all + * evaluations it is added to the database. + * + * @param event If a file is dropped on the scene. + * @throws IOException + */ + @FXML + void dragDrop(DragEvent event) throws IOException { + Dragboard db = event.getDragboard(); + boolean success = false; + if (db.hasFiles()) { + success = true; + String filePath; + //for loop allows for mutliple files to be dragged and dropped at once, if it ever happens. + for (File file : db.getFiles()) { + filePath = file.getAbsolutePath(); + String filename = file.getName(); + //get rid of the file extension if present, it messes with the db if its not removed. + if (file.getName().contains(".")) { + filename = filename.substring(0, filename.lastIndexOf('.')); + } + String fileNameTest = file.getName(); + Matcher filenametester = checkFileName.matcher(fileNameTest); + //check if the file name is inline with the database uses. + if (filenametester.find()) { + String content = Admin.getFullText(filePath); + Matcher matcher = checkCourseData.matcher(content); + //check if file actually contains course information or not before doing anything. + if (matcher.find()) { + File sourceFile = new File(filePath); + //File is moved to the right place in the programs file hierarchy, so it can be added to the database. + File destFile = new File("." + File.separator + "src" + File.separator + "ScheduleCreator" + File.separator + "resources" + File.separator + "raw" + File.separator + filename); + //If the file name and content checks out then it is added to the database. + if (sourceFile.renameTo(destFile)) { + Admin.regenDB(); + System.out.println("Sucess: file moved and was added to the database "); + Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "", ButtonType.OK); + alert.setTitle("Success"); + alert.setHeaderText("Success"); + alert.setContentText("Please go back to the schedule builder!"); + alert.showAndWait(); + } else { + //If for some reason the file was not moved correctly throw a error popup. + showError("File Not Moved", "The file was not scessfully moved, try again with a diffrent file!"); + System.out.println("Failed: file was not moved"); + } + //Throw error popup if the file does not contain course infomration. + } else { + showError("Invalid File Content", "The file does not contain valid course information, try again with a diffrent file!"); + System.out.println("the file does not contain valid course information"); + } + //Throw error popup if file name is not valid to what was specificed. + } else { + showError("Invalid File Name", "Rename the file and try again.\n *Semester should be lowercase directly followed by year with no spaces.\nExamples of valid file names.. \"fall2020\",\"spring3020\",\"summer2015\"...etc"); + System.out.println("file name is not valid for the database"); + } + } + } + event.setDropCompleted(success); + event.consume(); + } + + /** + * Handles when a file is dragged over the scene. + */ + @FXML + void dragOver(DragEvent event) { + Dragboard db = event.getDragboard(); + if (db.hasFiles()) { + event.acceptTransferModes(TransferMode.COPY); + } else { + event.consume(); + } + } + + /** + * Allows for error popups to be reproduced easily. + * + * @param _popupMessage1 Title and Simple message of error popup. + * @param _popupMessage2 Full message for error popup. + */ + void showError(String _popupMessage1, String _popupMessage2) { + Alert alert = new Alert(Alert.AlertType.ERROR, "", ButtonType.OK); + alert.setTitle(_popupMessage1); + alert.setHeaderText(_popupMessage1); + alert.setContentText(_popupMessage2); + alert.showAndWait(); + } + +} diff --git a/ScheduleCreator/resources/views/UserUpdatedDB.fxml b/ScheduleCreator/resources/views/UserUpdatedDB.fxml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.SubScene?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.Region?> +<?import javafx.scene.text.Font?> +<?import javafx.scene.text.Text?> + +<AnchorPane id="AnchorPane" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ScheduleCreator.controllers.UserUpdatedDBController"> + <children> + <Text layoutX="65.0" layoutY="57.0" strokeType="OUTSIDE" strokeWidth="0.0" text="How to Add New Semesters to the Database" wrappingWidth="650.9179649353027"> + <font> + <Font name="System Bold" size="29.0" /> + </font></Text> + <Text layoutX="100.0" layoutY="115.0" strokeType="OUTSIDE" strokeWidth="0.0" text="1. Go to the &quot;Registration&quot; tab in the menu."> + <font> + <Font size="18.0" /> + </font></Text> + <Text layoutX="100.0" layoutY="152.0" strokeType="OUTSIDE" strokeWidth="0.0" text="2. Click on &quot;Detailed Class Schedule&quot; and select the desired semester." wrappingWidth="610.91796875"> + <font> + <Font size="18.0" /> + </font></Text> + <Text layoutX="100.0" layoutY="188.0" strokeType="OUTSIDE" strokeWidth="0.0" text="3. Highlight everything in the &quot;Subject&quot; box, then click &quot;Class Search&quot; at the bottom of the page" wrappingWidth="591.2802791595459"> + <font> + <Font size="18.0" /> + </font></Text> + <Text layoutX="100.0" layoutY="241.0" strokeType="OUTSIDE" strokeWidth="0.0" text="4. Copy the enitre page" wrappingWidth="457.20605850219727"> + <font> + <Font size="18.0" /> + </font></Text> + <Text layoutX="99.0" layoutY="330.0" strokeType="OUTSIDE" strokeWidth="0.0" text="5. Create a new text file, paste everything copied in the pervious step, name* and save the file." wrappingWidth="636.2802734375"> + <font> + <Font size="18.0" /> + </font></Text> + <Text layoutX="143.0" layoutY="269.0" strokeType="OUTSIDE" strokeWidth="0.0" text="(cmd+a on mac &amp; crtl+a on windows to highlight everything)"> + <font> + <Font size="15.0" /> + </font></Text> + <Text layoutX="143.0" layoutY="289.0" strokeType="OUTSIDE" strokeWidth="0.0" text="(cmd+c on mac &amp; ctrl+c on windows to copy) "> + <font> + <Font size="15.0" /> + </font></Text> + <Text layoutX="139.0" layoutY="383.0" strokeType="OUTSIDE" strokeWidth="0.0" text="*File name should be lower case and contain no spaces (ex. spring2020, fall2025)"> + <font> + <Font size="15.0" /> + </font></Text> + <Text layoutX="99.0" layoutY="419.0" strokeType="OUTSIDE" strokeWidth="0.0" text="6. If all pervious steps were done correctly, you can drag and drop your text file on the current screen and it will be added to the database!" wrappingWidth="658.91796875"> + <font> + <Font name="System Bold" size="18.0" /> + </font> + </Text> + <SubScene height="567.0" layoutX="3.0" layoutY="1.0" onDragDropped="#dragDrop" onDragOver="#dragOver" opacity="0.0" width="829.0"> + <root> + <Region /> + </root> + </SubScene> + </children> +</AnchorPane> diff --git a/ScheduleCreator/resources/views/primary.fxml b/ScheduleCreator/resources/views/primary.fxml @@ -14,65 +14,65 @@ <?import javafx.scene.text.Text?> <StackPane xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ScheduleCreator.controllers.PrimaryController"> - <children> - <GridPane fx:id="mainBox"> - <columnConstraints> - <ColumnConstraints hgrow="ALWAYS" maxWidth="63.0" minWidth="0.0" prefWidth="63.0" /> - <ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="-Infinity" /> - </columnConstraints> - <rowConstraints> - <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> - </rowConstraints> - <children> - <GridPane alignment="CENTER" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS" HBox.hgrow="NEVER"> - <columnConstraints> - <ColumnConstraints hgrow="ALWAYS" /> - <ColumnConstraints /> - </columnConstraints> - <rowConstraints> - <RowConstraints fillHeight="false" maxHeight="200.0" minHeight="0.0" prefHeight="60.0" vgrow="NEVER" /> - <RowConstraints minHeight="10.0" prefHeight="666.0" vgrow="SOMETIMES" /> - </rowConstraints> - <children> - <Text layoutX="186.0" layoutY="54.0" strokeType="OUTSIDE" strokeWidth="0.0" text="UNCG Schedule Creator" wrappingWidth="451.1748046875" GridPane.columnSpan="2" GridPane.halignment="CENTER" GridPane.valignment="CENTER"> - <font> - <Font name="System Italic" size="37.0" /> - </font> - </Text> - <VBox prefHeight="169.0" prefWidth="275.0" spacing="10.0" GridPane.rowIndex="1"> - <children> - <StackPane fx:id="mainContent" prefHeight="150.0" VBox.vgrow="ALWAYS" /> + <children> + <GridPane fx:id="mainBox"> + <columnConstraints> + <ColumnConstraints hgrow="ALWAYS" maxWidth="63.0" minWidth="0.0" prefWidth="63.0" /> + <ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308" minWidth="-Infinity" /> + </columnConstraints> + <rowConstraints> + <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> + </rowConstraints> + <children> + <GridPane alignment="CENTER" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS" HBox.hgrow="NEVER"> + <columnConstraints> + <ColumnConstraints hgrow="ALWAYS" /> + <ColumnConstraints /> + </columnConstraints> + <rowConstraints> + <RowConstraints fillHeight="false" maxHeight="200.0" minHeight="0.0" prefHeight="60.0" vgrow="NEVER" /> + <RowConstraints minHeight="10.0" prefHeight="666.0" vgrow="SOMETIMES" /> + </rowConstraints> + <children> + <Text layoutX="186.0" layoutY="54.0" strokeType="OUTSIDE" strokeWidth="0.0" text="UNCG Schedule Creator" wrappingWidth="451.1748046875" GridPane.columnSpan="2" GridPane.halignment="CENTER" GridPane.valignment="CENTER"> + <font> + <Font name="System Italic" size="37.0" /> + </font> + </Text> + <VBox prefHeight="169.0" prefWidth="275.0" spacing="10.0" GridPane.rowIndex="1"> + <children> + <StackPane fx:id="mainContent" prefHeight="150.0" VBox.vgrow="ALWAYS" /> - </children> - </VBox> - <ToggleButton fx:id="darkMode" mnemonicParsing="false" onAction="#toggleDarkMode" text="Dark Mode" GridPane.halignment="RIGHT" /> - </children> - </GridPane> - <VBox fx:id="menuBox" alignment="CENTER" fillWidth="false" layoutX="57.0" layoutY="39.0" maxWidth="200.0" minHeight="200.0" minWidth="0.0" prefHeight="727.0" prefWidth="34.0" spacing="10.0" style="-fx-background-color:rgb(6,42,87);" visible="false" SplitPane.resizableWithParent="false"> - <children> - <HBox fx:id="schedMenuItem" alignment="CENTER" onMouseClicked="#changeToSelectCourses" onMouseEntered="#hoverItem" onMouseExited="#unhoverItem" prefHeight="50.0" prefWidth="200.0" style="-fx-background-color: rgb(229,191,16); -fx-border-color: black;"> - <children> - <Label fx:id="schedMenuItemLabel" alignment="CENTER" contentDisplay="CENTER" text="Build Schedule" /> - </children> - </HBox> - <HBox fx:id="advMenuItem" alignment="CENTER" maxWidth="1.7976931348623157E308" onMouseEntered="#hoverItem" onMouseExited="#unhoverItem" style="-fx-background-color: rgb(229,191,16); -fx-border-color: black;"> - <children> - <Label fx:id="advMenuItemLabel" alignment="CENTER" contentDisplay="CENTER" maxWidth="1.7976931348623157E308" prefHeight="50.0" prefWidth="200.0" text="Contact Advisor" /> - </children> - </HBox> - <HBox fx:id="regMenuItem" alignment="CENTER" onMouseClicked="#changeToRegistrationScreen" onMouseEntered="#hoverItem" onMouseExited="#unhoverItem" style="-fx-background-color: rgb(229,191,16); -fx-border-color: black;"> - <children> - <Label fx:id="regMenuItemLabel" alignment="CENTER" contentDisplay="CENTER" prefHeight="50.0" prefWidth="200.0" text="Registration" /> - </children> - </HBox> - </children> - </VBox> - </children> - </GridPane> - <ToggleButton fx:id="toggleMenu" mnemonicParsing="false" onAction="#toggleMenu" text="Menu" StackPane.alignment="TOP_LEFT"> - <StackPane.margin> - <Insets left="15.0" top="15.0" /> - </StackPane.margin> - </ToggleButton> - </children> + </children> + </VBox> + <ToggleButton fx:id="darkMode" mnemonicParsing="false" onAction="#toggleDarkMode" text="Dark Mode" GridPane.halignment="RIGHT" /> + </children> + </GridPane> + <VBox fx:id="menuBox" alignment="CENTER" fillWidth="false" layoutX="57.0" layoutY="39.0" maxWidth="200.0" minHeight="200.0" minWidth="0.0" prefHeight="727.0" prefWidth="34.0" spacing="10.0" style="-fx-background-color:rgb(6,42,87);" visible="false" SplitPane.resizableWithParent="false"> + <children> + <HBox fx:id="schedMenuItem" alignment="CENTER" onMouseClicked="#changeToSelectCourses" onMouseEntered="#hoverItem" onMouseExited="#unhoverItem" prefHeight="50.0" prefWidth="200.0" style="-fx-background-color: rgb(229,191,16); -fx-border-color: black;"> + <children> + <Label fx:id="schedMenuItemLabel" alignment="CENTER" contentDisplay="CENTER" text="Build Schedule" /> + </children> + </HBox> + <HBox fx:id="regMenuItem" alignment="CENTER" onMouseClicked="#changeToRegistrationScreen" onMouseEntered="#hoverItem" onMouseExited="#unhoverItem" style="-fx-background-color: rgb(229,191,16); -fx-border-color: black;"> + <children> + <Label fx:id="regMenuItemLabel" alignment="CENTER" contentDisplay="CENTER" prefHeight="50.0" prefWidth="200.0" text="Registration" /> + </children> + </HBox> + <HBox fx:id="dbItem" alignment="CENTER" onMouseClicked="#changeToDBScreen" onMouseEntered="#hoverItem" onMouseExited="#unhoverItem" style="-fx-background-color: rgb(229,191,16); -fx-border-color: black;"> + <children> + <Label fx:id="dbItemLabel" alignment="CENTER" contentDisplay="CENTER" prefHeight="50.0" prefWidth="200.0" text="Add to Database" /> + </children> + </HBox> + </children> + </VBox> + </children> + </GridPane> + <ToggleButton fx:id="toggleMenu" mnemonicParsing="false" onAction="#toggleMenu" text="Menu" StackPane.alignment="TOP_LEFT"> + <StackPane.margin> + <Insets left="15.0" top="15.0" /> + </StackPane.margin> + </ToggleButton> + </children> </StackPane>