package com.example.portfolio2; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.TextArea; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; import java.io.IOException; import java.sql.*; import java.util.ArrayList; import java.util.List; public class HelloApplication extends Application { // Initializing model, controller and database objects private Model model = new Model(); private Controller con = new Controller(model,this); MyDB myDB = new MyDB(); /* Below is the original implementation of the UI elements with accompanying, individual calls to setOnAction to specify functionality. Before changing to a list format, we made sure methods in controller and model were generalized to allow for the new structure seamlessly. private ComboBox programCombo = new ComboBox<>(); private ComboBox subject1Combo = new ComboBox<>(); private ComboBox subject2Combo = new ComboBox<>(); private ComboBox electiveCombo = new ComboBox<>(); private ComboBox programSelect = new ComboBox<>(); private ComboBox subject1Select = new ComboBox<>(); private ComboBox subject2Select = new ComboBox<>(); private ComboBox electiveSelect = new ComboBox<>(); private TextArea programArea = new TextArea(); private TextArea subject1Area = new TextArea(); private TextArea subject2Area = new TextArea(); private TextArea electiveArea = new TextArea(); private Label programEcts = new Label(); private Label subject1Ects = new Label(); private Label subject2Ects = new Label(); private Label electiveEcts = new Label(); private VBox program = new VBox(new Label("Program"), programCombo, programSelect, programArea, programEcts); private VBox subject1 = new VBox(new Label("Subject 1"), subject1Combo, subject1Select, subject1Area, subject1Ects); private VBox subject2 = new VBox(new Label("Subject 2"), subject2Combo, subject2Select, subject2Area, subject2Ects); private VBox elective = new VBox(new Label("Elective"), electiveCombo, electiveSelect, electiveArea, electiveEcts); */ @Override public void start(Stage stage) throws IOException { // Clears old insertions into the participation table con.initialize(); // Defines a list of columns based on their names. List columns = List.of( new ActivityColumn("Program"), new ActivityColumn("Subject 1"), new ActivityColumn("Subject 2"), new ActivityColumn("Elective") ); // Defines a list of subject modules List subjectModules = List.of("Computer Science", "Informatik", "Astrology"); // Loop for defining button funtionality for each activity column for (ActivityColumn col : columns) { col.nameLabel.setStyle("-fx-font-size: 18px; -fx-padding: 10px;"); // Styling col.ectsLabel.setStyle("-fx-font-size: 18px; -fx-padding: 10px"); col.categoryCombo.setPrefSize(250, 35); col.activitySelect.setPrefSize(250, 35); col.area.setPrefWidth(250); // All boxes share the same activity logic col.activitySelect.setOnAction(event -> { con.onActivitySelected(col.categoryCombo, col.activitySelect, col.area); con.updateEcts(col.ectsLabel, col.categoryCombo); }); switch (col.name) { // Switch statement handles different category boxes case "Program" -> { col.categoryCombo.getItems().addAll("HumTek", "NatBach"); col.categoryCombo.setOnAction(event -> { con.onComboSelected(col.categoryCombo, col.activitySelect, col.area); }); } case "Subject 1" -> { // We considered using the list for filling the box but couldn't figure it out col.categoryCombo.getItems().addAll("Computer Science", "Informatik", "Astrology"); col.categoryCombo.setOnAction(event -> { con.onSubjectModuleSelected(col.categoryCombo, columns.get(2).categoryCombo, subjectModules); con.onComboSelected(col.categoryCombo, col.activitySelect, col.area); }); } case "Subject 2" -> { col.categoryCombo.getItems().addAll("Computer Science", "Informatik", "Astrology"); col.categoryCombo.setOnAction(event -> { // We figured we have to specify // the second column like this but reckon there's a better way. con.onSubjectModuleSelected(col.categoryCombo, columns.get(1).categoryCombo, subjectModules); con.onComboSelected(col.categoryCombo, col.activitySelect, col.area); }); } case "Elective" -> { col.categoryCombo.setVisible(false); // Hide useless box con.fillElective(col.activitySelect); } } } // Define an HBox based on the columns and define the scene based on it. HBox root = new HBox(columns.get(0).asVBox(), columns.get(1).asVBox(), columns.get(2).asVBox(), columns.get(3).asVBox()); Scene scene = new Scene(root, 1000, 500); stage.setTitle("Course Selector RUC: Ultimate Deluxe Edition"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(); } // Class for each column of activities private class ActivityColumn { // Each column contains these elements String name; Label nameLabel; ComboBox categoryCombo; ComboBox activitySelect; TextArea area; Label ectsLabel; ActivityColumn(String name) { this.name = name; nameLabel = new Label(name); categoryCombo = new ComboBox<>(); activitySelect = new ComboBox<>(); area = new TextArea(); ectsLabel = new Label(); // new column, "this.name" to define and saved in the text felt, // new "nameLabel" to show visual text. // CategoryCombo creat a dropdown list // activitySelect creat one more dropdown list with Combobox, possible to choose activity. // area = new TextArea helps create a text felt to describe the chosen activity // ectsLabel = new Label shows text for ects points } VBox asVBox() { return new VBox(nameLabel, categoryCombo, activitySelect, area, ectsLabel); } } } class Controller{ private Model model; private HelloApplication view; // We do this without using the view directly like this, instead passing options. void initialize() { // calls on the database model.initialize(); } Controller(Model model, HelloApplication view){ this.model=model; this.view=view; } void onComboSelected(ComboBox combo, ComboBox select, TextArea area) { select.getItems().clear(); // Clear the activity selection box area.clear(); // Clear text area select.getItems().addAll(model.selectProgram((String) combo.getValue())); // Fill activity box using model method } void onActivitySelected(ComboBox combo, ComboBox select, TextArea area) { addActivity((String) select.getValue(), area); // Passes the value chosen in the box updateArea(combo, area); // Updates the text area based on the category choice // users can choose from the ComboBox, string (activity) and the area would update. } void onSubjectModuleSelected(ComboBox subject1, ComboBox subject2, List subjectModules) { // Beautiful loop we've created to remove option chosen in one subject module box from the other for (String sub : subjectModules) { if (sub.equals(subject1.getValue())) { subject2.getItems().remove(subject1.getValue()); } else if (!sub.equals(subject1.getValue()) && !subject2.getItems().contains(sub)) { subject2.getItems().add(sub); } } } void addActivity(String s, TextArea textArea) { // Calls on model method to add participation in the database model.addParticipation(model.getActivityIndeks(s)); } void updateArea(ComboBox combo, TextArea textArea) { // Clears the text area and adds all activity names from activities in participation textArea.clear(); for(String s : model.getParticipation((String) combo.getValue())) { textArea.appendText(s + "\n"); } } void updateEcts(Label ectslabel, ComboBox comboBox) { // Updates the labels with the current ECTS of the program type ectslabel.setText("ECTS: "+model.getSumEcts(comboBox.getValue())); } void fillElective(ComboBox electiveBox) { electiveBox.getItems().addAll(model.getAllActivities()); } } class Model{ // The model handles all interactions with the database MyDB db=new MyDB(); Model(){} void initialize() { // When running the program, it clears the participation database clearParticipation(); } int getActivityIndeks(String name) { // Returns the integer value of the activity's index if(name ==null) return -1; ArrayList result = db.query("select indeks from activity a where name is '"+name+"';", "indeks"); return Integer.parseInt(result.getFirst()); } void addParticipation(int activityIndex) { // Inserts the given activity into participation using the activity's index db.cmd("insert into participation values(123, "+activityIndex+");"); } ArrayList getParticipation(String program) { // Returns all activity names from activities currently in participation return db.query("select name from participation p inner join activity a on p.indeks = a.indeks where program is '" + program + "';", "name"); } void clearParticipation() { // Removes all entries in the participation database db.cmd("delete from participation"); } ArrayList selectProgram(String program) { // Returns an arraylist of activities within the given program return db.query("select name from activity where program is '" + program + "';", "name"); } String getSumEcts(String program){ // Returns the sum of ECTS points under the given category from the student as a string if(program==null)return "0"; ArrayList result = db.query("select sum(activity.ects) as total_ects,student.name from student left outer join participation on student.studid = participation.studid inner join activity on participation.indeks = activity.indeks where program is '"+program+"' group by student.studid ;", "total_ects"); if (result.isEmpty()) return "0"; return result.getFirst(); } ArrayList getAllActivities() { return db.query("select name from activity;", "name"); } } class MyDB { // MyDB is all standard Database configuration that was gotten from Mads Connection conn = null; MyDB() { if (conn == null) open(); } public void open() { try { String url = "jdbc:sqlite:identifier.sqlite"; conn = DriverManager.getConnection(url); } catch (SQLException e) { System.out.println("cannot open"); if (conn != null) close(); throw new RuntimeException(e); } ; } public void close() { try { if (conn != null) conn.close(); } catch (SQLException e) { throw new RuntimeException(e); } conn = null; } public void cmd(String sql) { if (conn == null) open(); if (conn == null) { System.out.println("No connection"); return; } Statement stmt = null; try { stmt = conn.createStatement(); stmt.executeUpdate(sql); } catch (SQLException e) { System.out.println("Error in statement " + sql); throw new RuntimeException(e); } try { if (stmt != null) { stmt.close(); } } catch (SQLException e) { System.out.println("Error in statement " + sql); throw new RuntimeException(e); } } public ArrayList query(String query, String fld) { ArrayList res = new ArrayList<>(); if (conn == null) open(); if (conn == null) { System.out.println("No connection"); throw new RuntimeException("No connection"); } Statement stmt = null; try { stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(query); while (rs.next()) { String name = rs.getString(fld); res.add(name); } } catch (SQLException e) { System.out.println("Error in statement " + query + " " + fld); throw new RuntimeException(e); } try { if (stmt != null) { stmt.close(); } } catch (SQLException e) { System.out.println("Error in statement " + query + " " + fld); throw new RuntimeException(e); } return res; } }