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

CoursesController.java (25119B)


      1 package ScheduleCreator.controllers;
      2 
      3 /**
      4  * This class controls interactions in the Courses View.
      5  *
      6  * @author Jamison Valentine, Ilyass Sfar, Nick Econopouly, Nathan Tolodziecki
      7  *
      8  * Last Updated: 5/05/2020
      9  */
     10 import ScheduleCreator.Adapter;
     11 import java.io.IOException;
     12 import java.net.URL;
     13 import java.util.ArrayList;
     14 import java.util.List;
     15 import java.util.ResourceBundle;
     16 import java.util.logging.Level;
     17 import java.util.logging.Logger;
     18 import java.util.regex.Matcher;
     19 import java.util.regex.Pattern;
     20 import ScheduleCreator.models.Course;
     21 import ScheduleCreator.models.Schedule;
     22 import ScheduleCreator.models.Section;
     23 import ScheduleCreator.models.Semester;
     24 import java.util.Arrays;
     25 import javafx.collections.FXCollections;
     26 import javafx.collections.ObservableList;
     27 import javafx.collections.transformation.FilteredList;
     28 import javafx.event.ActionEvent;
     29 import javafx.fxml.FXML;
     30 import javafx.fxml.FXMLLoader;
     31 import javafx.fxml.Initializable;
     32 import javafx.geometry.HPos;
     33 import javafx.geometry.Insets;
     34 import javafx.geometry.Pos;
     35 import javafx.geometry.VPos;
     36 import javafx.scene.Scene;
     37 import javafx.scene.control.Alert;
     38 import javafx.scene.control.Button;
     39 import javafx.scene.control.ButtonType;
     40 import javafx.scene.control.CheckBox;
     41 import javafx.scene.control.ComboBox;
     42 import javafx.scene.control.Label;
     43 import javafx.scene.control.ListView;
     44 import javafx.scene.control.ScrollPane;
     45 import javafx.scene.control.Tab;
     46 import javafx.scene.control.TabPane;
     47 import javafx.scene.control.TextArea;
     48 import javafx.scene.control.TextField;
     49 import javafx.scene.layout.BorderPane;
     50 import javafx.scene.layout.GridPane;
     51 import javafx.scene.layout.Priority;
     52 import javafx.scene.layout.StackPane;
     53 import javafx.scene.layout.VBox;
     54 import javafx.scene.shape.Rectangle;
     55 import javafx.stage.Stage;
     56 
     57 public class CoursesController implements Initializable {
     58 
     59     @FXML
     60     private ComboBox<String> semesterComboBox;
     61     @FXML
     62     private TextField searchField;
     63     @FXML
     64     private ListView availableCourses, selectedCoursesListView, sectionListView;
     65     @FXML
     66     private Button removeCourseButton;
     67     @FXML
     68     private GridPane scheduleGridPane;
     69     @FXML
     70     private Label scheduleLabel, onlineClassesLabel;
     71     @FXML
     72     private TabPane sectionTabPane;
     73     @FXML
     74     private VBox CRNContainer, CRNPane;
     75 
     76     // the following buttons are only here for the buttonSetup() method
     77     @FXML
     78     private Button addCourseButton, removeAllCoursesButton, selectAllButton,
     79             previousButton, nextButton, showCRNButton, emailCRNButton, sectionsButton;
     80 
     81     // List of courses for current semester.
     82     private FilteredList<String> courseList;
     83 
     84     protected static Semester currentSemester;
     85     private Course focusedCourse;
     86     private Adapter adapter = new Adapter();
     87 
     88     private int NUM_ROWS;
     89     private int NUM_COLS;
     90     protected static int currentScheduleIndex;
     91 
     92     private BorderPane[][] grid;
     93     private List<BorderPane> entries = new ArrayList();
     94 
     95     /**
     96      * Set up the "Build Schedule" view and load the semesters.
     97      *
     98      * @param url
     99      * @param rb
    100      */
    101     @Override
    102     public void initialize(URL url, ResourceBundle rb) {
    103         try {
    104             this.loadSemesters();
    105             this.NUM_ROWS = this.scheduleGridPane.getRowConstraints().size();
    106             this.NUM_COLS = this.scheduleGridPane.getColumnConstraints().size();
    107             this.grid = new BorderPane[this.NUM_ROWS][this.NUM_COLS];
    108             this.drawGrid();
    109             this.CRNPane.toFront();
    110 
    111             // final tweaks to make buttons keyboard-navigable
    112             this.buttonSetup();
    113 
    114         } catch (Exception ex) {
    115             Logger.getLogger(CoursesController.class.getName()).log(Level.SEVERE, null, ex);
    116         }
    117     }
    118 
    119     /**
    120      * Run the action for each button if it's selected and the user types
    121      * "Enter"
    122      */
    123     private void buttonSetup() {
    124         Arrays.asList(this.addCourseButton, this.removeCourseButton,
    125                 this.removeAllCoursesButton, this.selectAllButton,
    126                 this.sectionsButton, this.previousButton, this.nextButton,
    127                 this.showCRNButton, this.emailCRNButton).forEach((button) -> {
    128                     // temporarily set the button as the default button (only while the button is in focus)
    129                     // https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/Button.html#defaultButtonProperty
    130                     button.defaultButtonProperty().bind(button.focusedProperty());
    131                 });
    132     }
    133 
    134     /**
    135      * Called when "Add Course" button is clicked; Add selected course to the
    136      * listview and saves in database.
    137      *
    138      * @param _event
    139      */
    140     public void addSelectedCourse(ActionEvent _event) {
    141 
    142         if (this.availableCourses.getFocusModel().getFocusedItem() != null) {
    143             String selectedCourse = this.availableCourses.getFocusModel().getFocusedItem().toString();
    144             Course newCourse = new Course(selectedCourse, CoursesController.currentSemester.getName());
    145             if (CoursesController.currentSemester.addCourse(newCourse)) {
    146                 this.selectedCoursesListView.getItems().add(selectedCourse);
    147                 CoursesController.currentSemester.generateSchedules();
    148                 this.createNewTab(newCourse);
    149             }
    150             this.regenerateSchedules();
    151         }
    152     }
    153 
    154     /**
    155      * Called when "Submit" button is clicked; update the list of selected
    156      * sections for generating schedules.
    157      *
    158      * @param _event
    159      */
    160     public void setSections(ActionEvent _event) {
    161 
    162         Course course;
    163         Tab tab;
    164         for (int i = 0; i < this.sectionTabPane.getTabs().size(); i++) {
    165             tab = this.sectionTabPane.getTabs().get(i);
    166             course = CoursesController.currentSemester.getSelectedCourses().get(i);
    167             List<Section> selected = new ArrayList();
    168             VBox container = (VBox) ((ScrollPane) tab.getContent()).getContent();
    169             for (int j = 0; j < container.getChildren().size(); j++) {
    170                 VBox entry = (VBox) container.getChildren().get(j);
    171                 CheckBox checkBox = (CheckBox) entry.getChildren().get(0);
    172                 if (checkBox.isSelected()) {
    173                     selected.add(course.getSections().get(j));
    174                 }
    175             }
    176             CoursesController.currentSemester.getSelectedSections().put(course, selected);
    177         }
    178         this.regenerateSchedules();
    179     }
    180 
    181     /**
    182      * Called when a different semester is chosen and loads semester and course
    183      * list.
    184      *
    185      * @param _event
    186      */
    187     public void switchSemester(ActionEvent _event) {
    188 
    189         String currentSemesterString = this.semesterComboBox.getValue();
    190         CoursesController.currentSemester = new Semester(semesterDirName(currentSemesterString));
    191 
    192         this.loadAllCourses();
    193         this.loadSelectedCourses();
    194 
    195         // Renders the first generated schedule if there is at least 1 selected course.
    196         if (CoursesController.currentSemester.getSelectedCourses().size() > 0) {
    197             this.loadSchedule(CoursesController.currentSemester.getSchedules().get(0));
    198         }
    199     }
    200 
    201     /**
    202      * Formats given string to appropriate semester directory name
    203      *
    204      * @param _semester
    205      * @return
    206      */
    207     public String semesterDirName(String _semester) {
    208 
    209         String[] temp = _semester.split(" ");
    210         String formattedSemester = temp[0].toLowerCase() + temp[1];
    211         return formattedSemester;
    212     }
    213 
    214     /**
    215      * Clears the current displayed schedule.
    216      */
    217     public void clearScheduleGrid() {
    218         this.entries.forEach((entry) -> {
    219             this.scheduleGridPane.getChildren().remove(entry);
    220         });
    221         this.entries.clear();
    222     }
    223 
    224     /**
    225      * Removes the selected course from the listview and the database.
    226      *
    227      * @param _event
    228      */
    229     public void removeSelectedCourse(ActionEvent _event) {
    230 
    231         if (this.selectedCoursesListView.getSelectionModel().getSelectedItem() != null) {
    232             int index = this.selectedCoursesListView.getSelectionModel().getSelectedIndex();
    233             this.sectionTabPane.getTabs().remove(index);
    234             String courseToRemove = ((String) this.selectedCoursesListView.getSelectionModel().getSelectedItem()).trim();
    235             this.selectedCoursesListView.getItems().remove(courseToRemove);
    236             CoursesController.currentSemester.removeCourse(courseToRemove);
    237 
    238             // Clears the section listview if the focus is on the course to be removed.
    239             if (this.focusedCourse != null && this.focusedCourse.getFullText().equalsIgnoreCase(courseToRemove)) {
    240                 this.sectionListView.getItems().clear();
    241             }
    242 
    243             CoursesController.currentSemester.generateSchedules();
    244             this.regenerateSchedules();
    245         }
    246     }
    247 
    248     /*
    249      * Remove all selected courses from the ListView (and reload the UI)
    250      */
    251     public void removeAllCourses(ActionEvent _event) {
    252         List<String> courses = CoursesController.currentSemester.getSelectedCourseStrings();
    253 
    254         courses.forEach((course) -> {
    255             CoursesController.currentSemester.removeCourse(course);
    256         });
    257 
    258         CoursesController.currentSemester.generateSchedules();
    259         this.regenerateSchedules();
    260         this.loadSelectedCourses();
    261     }
    262 
    263     /**
    264      * Generates all possible schedules consisting of selected sections.
    265      */
    266     public void regenerateSchedules() {
    267         CoursesController.currentSemester.generateSchedules();
    268         this.clearScheduleGrid();
    269 
    270         if (CoursesController.currentSemester.getNumberOfSchedules() == 0) {
    271             this.scheduleLabel.setText("0/0");
    272         } else if (CoursesController.currentSemester.getNumberOfSchedules() > 0) {
    273             this.loadSchedule(CoursesController.currentSemester.getSchedules().get(0));
    274             this.scheduleLabel.setText("1/" + CoursesController.currentSemester.getNumberOfSchedules());
    275         }
    276     }
    277 
    278     /**
    279      * Gets sections for a selected course and adds them to the sections
    280      * listview.
    281      *
    282      * @param _event
    283      */
    284     public void loadCourseSections(ActionEvent _event) {
    285 
    286         // Do nothing if no course has been selected.
    287         if (this.selectedCoursesListView.getSelectionModel().getSelectedItem() == null) {
    288             return;
    289         }
    290 
    291         String currentSelection = this.selectedCoursesListView.getSelectionModel().getSelectedItem().toString();
    292 
    293         // Get the corresponding course to reference for sections
    294         for (Course course : CoursesController.currentSemester.getSelectedCourses()) {
    295             if (course.getFullText().equals(currentSelection)) {
    296                 this.focusedCourse = course;
    297                 break;
    298             }
    299         }
    300 
    301         List<String> listCellLabels = new ArrayList();
    302 
    303         this.focusedCourse.getSections().forEach((section) -> {
    304             listCellLabels.add(section.toString());
    305         });
    306 
    307         this.sectionListView.setItems(FXCollections.observableList(listCellLabels));
    308 
    309     }
    310 
    311     /*
    312      * Load list of courses into the availableCourses ListBox
    313      */
    314     public void loadAllCourses() {
    315 
    316         // intermediary ObservableList of the courses
    317         ObservableList<String> OList = FXCollections.observableList(CoursesController.currentSemester.getAllCourses());
    318 
    319         // create FilteredList that we'll actually use
    320         this.courseList = new FilteredList<>(OList, s -> true);
    321 
    322         // connect availableCourses ListView to the courseList
    323         this.availableCourses.setItems(this.courseList);
    324 
    325         // Connect search bar filtering to the courseList FilteredList (this uses
    326         // lambdas, it's adapted from
    327         // https://stackoverflow.com/questions/28448851/how-to-use-javafx-filteredlist-in-a-listview
    328         // and
    329         // https://stackoverflow.com/questions/45045631/filter-items-within-listview-in-javafx
    330         // )
    331         searchField.textProperty().addListener(obs -> {
    332 
    333             String filter = this.searchField.getText().toLowerCase();
    334             // when there's nothing entered yet
    335             if (filter == null || filter.length() == 0) {
    336                 // show all courses
    337                 this.courseList.setPredicate(s -> true);
    338                 // otherwise
    339             } else {
    340                 // filter based on the contents of the search bar
    341                 this.courseList.setPredicate(s -> s.toLowerCase().contains(filter));
    342             }
    343         });
    344     }
    345 
    346     /**
    347      * Load list of semesters and show them in the dropdown menu
    348      *
    349      * @throws IOException
    350      */
    351     public void loadSemesters() throws IOException {
    352         List<String> semesters = this.adapter.getSemesters();
    353 
    354         List<String> newList = new ArrayList();
    355         Pattern p = Pattern.compile("([a-z]*)([0-9]{4})");
    356         Matcher m;
    357 
    358         String formattedSemester = "";
    359         for (String semester : semesters) {
    360             m = p.matcher(semester);
    361 
    362             if (m.matches()) {
    363                 formattedSemester = m.group(1).substring(0, 1).toUpperCase() + m.group(1).substring(1) + " " + m.group(2);
    364             }
    365             newList.add(formattedSemester);
    366         }
    367 
    368         this.semesterComboBox.setItems(FXCollections.observableList(newList));
    369     }
    370 
    371     /**
    372      * Refresh the tabbed section selection box
    373      */
    374     public void loadSelectedCourses() {
    375         this.sectionTabPane.getTabs().clear();
    376         this.selectedCoursesListView.setItems(FXCollections.observableList(CoursesController.currentSemester.getSelectedCourseStrings()));
    377 
    378         CoursesController.currentSemester.getSelectedCourses().forEach((course) -> {
    379             this.createNewTab(course);
    380         });
    381 
    382         this.regenerateSchedules();
    383     }
    384 
    385     /**
    386      * Creates new tab that display associated course sections.
    387      *
    388      * @param _course
    389      */
    390     public void createNewTab(Course _course) {
    391         Tab tab = new Tab();
    392         tab.setText(_course.getID());
    393         VBox content = new VBox();
    394         ScrollPane pane = new ScrollPane();
    395         _course.getSections().stream().map((section) -> {
    396             VBox sectionEntry = new VBox();
    397             sectionEntry.setPrefHeight(30);
    398             sectionEntry.setMinHeight(30);
    399             VBox.setVgrow(content, Priority.NEVER);
    400             sectionEntry.setAlignment(Pos.CENTER_LEFT);
    401             sectionEntry.setStyle("-fx-border-color: grey; -fx-border-width: 0 0 .5 0;");
    402             CheckBox checkBox = new CheckBox();
    403             checkBox.setSelected(true);
    404             VBox.setMargin(checkBox, new Insets(0, 0, 0, 10));
    405             checkBox.setText(section.toString());
    406             sectionEntry.getChildren().add(checkBox);
    407             return sectionEntry;
    408         }).forEachOrdered((sectionEntry) -> {
    409             content.getChildren().add(sectionEntry);
    410         });
    411         pane.setContent(content);
    412         tab.setContent(pane);
    413         this.sectionTabPane.getTabs().add(tab);
    414     }
    415 
    416     /**
    417      * If there are no selections, force select all; if there are any
    418      * selections, unselect all of them.
    419      *
    420      * @param _event
    421      */
    422     public void selectAll(ActionEvent _event) {
    423         if (this.sectionTabPane.getSelectionModel().getSelectedItem() == null) {
    424             return;
    425         }
    426         int index = this.sectionTabPane.getSelectionModel().getSelectedIndex();
    427         Tab currentTab = this.sectionTabPane.getTabs().get(index);
    428 
    429         if (this.allUnselected(currentTab)) {
    430             this.setSelectAll(true, currentTab);
    431         } else {
    432             this.setSelectAll(false, currentTab);
    433         }
    434     }
    435 
    436     /**
    437      * Returns true if all sections checkboxes are unchecked
    438      *
    439      * @param _tab
    440      */
    441     public boolean allUnselected(Tab _tab) {
    442 
    443         VBox container = (VBox) ((ScrollPane) _tab.getContent()).getContent();
    444         for (int j = 0; j < container.getChildren().size(); j++) {
    445             VBox entry = (VBox) container.getChildren().get(j);
    446             CheckBox checkBox = (CheckBox) entry.getChildren().get(0);
    447             if (checkBox.isSelected()) {
    448                 return false;
    449             }
    450         }
    451         return true;
    452     }
    453 
    454     /**
    455      * Check all of the section checkboxes
    456      *
    457      * @param _option
    458      * @param _tab
    459      */
    460     public void setSelectAll(boolean _option, Tab _tab) {
    461 
    462         VBox container = (VBox) ((ScrollPane) _tab.getContent()).getContent();
    463         for (int j = 0; j < container.getChildren().size(); j++) {
    464             VBox entry = (VBox) container.getChildren().get(j);
    465             CheckBox checkBox = (CheckBox) entry.getChildren().get(0);
    466             checkBox.setSelected(_option);
    467         }
    468     }
    469 
    470     /**
    471      * Draw the week schedule grid.
    472      */
    473     public void drawGrid() {
    474 
    475         for (int i = 1; i < this.NUM_ROWS; i++) {
    476             for (int j = 1; j < this.NUM_COLS; j++) {
    477                 BorderPane region = new BorderPane();
    478                 region.setStyle(("-fx-border-color: black; -fx-border-width: .5;"));
    479                 this.grid[i][j] = region;
    480                 this.scheduleGridPane.add(region, j, i);
    481             }
    482         }
    483     }
    484 
    485     /**
    486      * Show the current list of CRNs to the user when they click on the "Show
    487      * CRNs" button
    488      *
    489      * @param _event
    490      */
    491     public void showCRNs(ActionEvent _event) {
    492         if (CoursesController.currentSemester == null) {
    493             return;
    494         }
    495         if (CoursesController.currentSemester.getSelectedCourses().isEmpty()) {
    496             return;
    497         }
    498         this.CRNContainer.getChildren().clear();
    499         StringBuilder content = new StringBuilder();
    500         CoursesController.currentSemester.getSchedules().get(CoursesController.currentScheduleIndex).getAddedSections().forEach((section) -> {
    501             content.append(section.getID() + " - " + section.getCRN() + "\n");
    502         });
    503         TextArea textArea = new TextArea(content.toString());
    504         textArea.setEditable(false);
    505         this.CRNContainer.getChildren().add(textArea);
    506         this.CRNPane.setVisible(true);
    507         this.CRNPane.toFront();
    508     }
    509 
    510     /**
    511      * Hide the list of CRNs.
    512      */
    513     public void hideCRNs() {
    514         this.CRNPane.setVisible(false);
    515     }
    516 
    517     /**
    518      * Draw a colored box for a course in the week schedule.
    519      *
    520      * @param _section
    521      * @param _numberOfCampusCourses
    522      */
    523     public void addEntry(Section _section, int _numberOfCampusCourses) {
    524 
    525         String color = this.assignColor(_numberOfCampusCourses);
    526 
    527         int row = (int) _section.getStartTime() / 100 - 7;
    528         double topMargin = (_section.getStartTime() % 100) / 60;
    529         getDays(_section).forEach((col) -> {
    530             Label label = new Label(_section.getCourseID() + " - " + _section.getSectionNumber());
    531             BorderPane entryContainer = new BorderPane();
    532             entryContainer.paddingProperty().set(new Insets(this.grid[row][col].heightProperty().multiply(topMargin).doubleValue(), 0, 0, 0));
    533             StackPane pane = new StackPane();
    534 
    535             Rectangle rect = new Rectangle();
    536             rect.setStyle("-fx-fill:" + color + "; -fx-stroke: black; -fx-stroke-line-cap: round; -fx-arc-height: 10; -fx-arc-width: 10;");
    537             label.setAlignment(Pos.CENTER);
    538 
    539             pane.setStyle("");
    540             pane.getChildren().addAll(rect, label);
    541             entryContainer.setTop(pane);
    542 
    543             this.scheduleGridPane.getChildren().add(entryContainer);
    544             GridPane.setConstraints(entryContainer, col, row, 1, GridPane.REMAINING, HPos.CENTER, VPos.TOP);
    545             BorderPane region = this.grid[row][col];
    546             rect.heightProperty().bind(region.heightProperty().subtract(2).multiply(_section.getDurationHours()));
    547             rect.widthProperty().bind(region.widthProperty().subtract(2));
    548             this.entries.add(entryContainer);
    549         });
    550     }
    551 
    552     /**
    553      * Returns a list of meeting days for particular section.
    554      *
    555      * @param _section
    556      * @return
    557      */
    558     public List<Integer> getDays(Section _section) {
    559         char[] daysString = _section.getDays().toCharArray();
    560         ArrayList<Integer> days = new ArrayList();
    561         for (char day : daysString) {
    562             switch (day) {
    563                 case 'T':
    564                     days.add(2);
    565                     break;
    566                 case 'M':
    567                     days.add(1);
    568                     break;
    569                 case 'W':
    570                     days.add(3);
    571                     break;
    572                 case 'R':
    573                     days.add(4);
    574                     break;
    575                 case 'F':
    576                     days.add(5);
    577                     break;
    578             }
    579         }
    580         return days;
    581     }
    582 
    583     /**
    584      * Returns a different color for the next course on the grid.
    585      *
    586      * @param _numberOfCampusCourses
    587      * @return
    588      */
    589     public String assignColor(int _numberOfCampusCourses) {
    590         String color;
    591         switch (_numberOfCampusCourses) {
    592             case 1:
    593                 // green
    594                 color = "#ccffcc";
    595                 break;
    596             case 2:
    597                 // blue
    598                 color = "#b3e1ff";
    599                 break;
    600             case 3:
    601                 // red
    602                 color = "#ffb3b3 ";
    603                 break;
    604             case 4:
    605                 // yellow
    606                 color = "#e6e600";
    607                 break;
    608             case 5:
    609                 // orange
    610                 color = "#ffda75";
    611                 break;
    612             case 6:
    613                 color = "#ff6666";
    614                 break;
    615 
    616             default:
    617                 color = "lightblue";
    618         }
    619 
    620         return color;
    621     }
    622 
    623     /**
    624      * Update the grid and other UI elements on the right side to reflect the
    625      * currently selected sections.
    626      *
    627      * @param _schedule
    628      */
    629     public void loadSchedule(Schedule _schedule) {
    630         this.hideCRNs();
    631         this.clearScheduleGrid();
    632         int numberOfCampusCourses = 0;
    633         int onlineCourses = 0;
    634         StringBuilder label = new StringBuilder("Online Classes: ");
    635         for (Section section : _schedule.getAddedSections()) {
    636             if (!section.isOnline()) {
    637                 this.addEntry(section, ++numberOfCampusCourses);
    638             } else {
    639                 if (onlineCourses >= 1) {
    640                     label.append(" | ");
    641                 }
    642                 label.append(section.getID());
    643                 onlineCourses++;
    644             }
    645         }
    646         this.scheduleLabel.setText(CoursesController.currentScheduleIndex + 1 + "/" + CoursesController.currentSemester.getNumberOfSchedules());
    647         this.onlineClassesLabel.setText(label.toString());
    648     }
    649 
    650     /**
    651      * Load schedule for the next semester
    652      *
    653      * @param _event
    654      */
    655     public void loadNextSchedule(ActionEvent _event) {
    656         if (CoursesController.currentSemester != null) {
    657             if (CoursesController.currentScheduleIndex < CoursesController.currentSemester.getSchedules().size() - 1) {
    658                 CoursesController.currentScheduleIndex++;
    659                 this.loadSchedule(CoursesController.currentSemester.getSchedules().get(CoursesController.currentScheduleIndex));
    660             }
    661         }
    662     }
    663 
    664     /**
    665      * Load schedule for the previous semester
    666      *
    667      * @param _event
    668      */
    669     public void loadPrevSchedule(ActionEvent _event) {
    670         if (CoursesController.currentScheduleIndex > 0) {
    671             CoursesController.currentScheduleIndex--;
    672             this.loadSchedule(CoursesController.currentSemester.getSchedules().get(CoursesController.currentScheduleIndex));
    673         }
    674     }
    675 
    676     /**
    677      * Open the email popup for when the user clicks "Email CRN".
    678      *
    679      * @param event
    680      */
    681     public void popupAction(ActionEvent event) {
    682         //if no courses are selected, and the email button is pressed then thier is nothing to email, an error box is thrown
    683         if (CoursesController.currentSemester == null || CoursesController.currentSemester.getSelectedCourses().isEmpty()) {
    684             Alert alert = new Alert(Alert.AlertType.WARNING, "", ButtonType.OK);
    685             alert.setTitle("Warning");
    686             alert.setHeaderText("You have not selected any courses yet");
    687             alert.setContentText("Select a semseter and courses and try again!");
    688             alert.showAndWait();
    689             System.out.println("No semster or courses choosen.");
    690 
    691             //if the user does have a course selected and the email button is pressed, it shows as normal
    692         } else {
    693             try {
    694                 FXMLLoader fxmlLoader = new FXMLLoader();
    695                 fxmlLoader.setLocation(getClass().getResource("/ScheduleCreator/resources/views/email_popup.fxml"));
    696                 Scene scene = new Scene(fxmlLoader.load(), 450, 150);
    697                 Stage stage = new Stage();
    698                 stage.setTitle("Email Course Information");
    699                 stage.setScene(scene);
    700                 stage.show();
    701             } catch (IOException e) {
    702                 Logger logger = Logger.getLogger(getClass().getName());
    703                 logger.log(Level.SEVERE, "Failed to create new Window.", e);
    704             }
    705         }
    706     }
    707 
    708 }